【问题标题】:How to let a multi-processing python application quit cleanly如何让多处理 python 应用程序干净地退出
【发布时间】:2014-05-08 11:52:55
【问题描述】:

当我运行一个使用多处理的 python 脚本时,我发现当它收到 Ctrl-C 时很难让它干净地停止。 Ctrl-C 必须按多次,屏幕上会出现各种错误消息。

如何制作一个使用多处理并退出的 Python 脚本 收到 Ctrl-C 时是否干净?

以这个脚本为例

import numpy as np, time
from multiprocessing import Pool

def countconvolve(N):
    np.random.seed() # ensure seed is random

    count = 0
    iters = 1000000 # 1million

    l=12
    k=12
    l0=l+k-1

    for n in range(N):
        t = np.random.choice(np.array([-1,1], dtype=np.int8), size=l0 * iters)
        v = np.random.choice(np.array([-1,1], dtype=np.int8), size = l * iters)
        for i in xrange(iters):
            if (not np.convolve(v[(l*i):(l*(i+1))],
t[(l0*i):(l0*(i+1))], 'valid').any()):
                count += 1
    return count

if __name__ == '__main__':
    start = time.clock()

    num_processes = 8
    N = 13

    pool = Pool(processes=num_processes)
    res = pool.map(countconvolve, [N] * num_processes)
    print res, sum(res)

    print (time.clock() - start)

【问题讨论】:

  • 我会尝试编写一个signal handler 来捕获 ctrl-c 命中并终止生成的进程。

标签: python multiprocessing


【解决方案1】:

Jon 的解决方案可能更好,但这里使用的是信号处理程序。我在一个速度极慢的 VBox VM 中尝试了它,但确实有效。我希望它会有所帮助。

import numpy as np, time
from multiprocessing import Pool
import signal

# define pool as global
pool = None


def term_signal_handler(signum, frame):
    global pool

    print 'CTRL-C pressed'
    try:
        pool.close()
        pool.join()
    except AttributeError:
        print 'Pool has been already closed'


def countconvolve(N):
    np.random.seed() # ensure seed is random

    count = 0
    iters = 1000000 # 1million

    l=12
    k=12
    l0=l+k-1

    for n in range(N):
        t = np.random.choice(np.array([-1,1], dtype=np.int8), size=l0 * iters)
        v = np.random.choice(np.array([-1,1], dtype=np.int8), size = l * iters)
        for i in xrange(iters):
            if (not np.convolve(v[(l*i):(l*(i+1))],t[(l0*i):(l0*(i+1))], 'valid').any()):
                count += 1
    return count


if __name__ == '__main__':
    # Register the signal handler
    signal.signal(signal.SIGINT, term_signal_handler)

    start = time.clock()

    num_processes = 8
    N = 13

    pool = Pool(processes=num_processes)
    res = pool.map(countconvolve, [N] * num_processes)
    print res, sum(res)

    print (time.clock() - start)

【讨论】:

  • 我使用了信号处理程序来关闭线程,这对我来说是最干净的。
  • +1:我喜欢业务逻辑不必处理 CTRL+C 摆弄这一事实,但遗憾的是它需要一个全局变量才能工作:-/
【解决方案2】:

我相信a similar post here on SO 中提到的try-catch 可以适应它。

如果您将 pool.map 调用包装在 try-catch 中,然后调用 terminate 并加入,我认为就可以了。

[编辑]

一些实验表明,这些方面的某些东西效果很好:

from multiprocessing import Pool
import random
import time

def countconvolve(N):
    try:
        sleepTime = random.randint(0,5)
        time.sleep(sleepTime)
        count = sleepTime
    except KeyboardInterrupt as e:
        pass
    return count

if __name__ == '__main__':
    random.seed(0)
    start = time.clock()

    num_processes = 8
    N = 13

    pool = Pool(processes=num_processes)
    try:
        res = pool.map(countconvolve, [N] * num_processes)
        print res, sum(res)
        print (time.clock() - start)
    except KeyboardInterrupt as e:
        print 'Stopping..'

我稍微简化了您的示例以避免必须在我的机器上加载 numpy 进行测试,但关键部分是处理 CTRL+C 的两个 try-except 调用kbd> 按键。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-01
    • 2015-07-28
    • 1970-01-01
    • 2014-07-24
    • 1970-01-01
    相关资源
    最近更新 更多