質問

When I run a python script that uses multiprocessing I find it hard to get it to stop cleanly when it receives Ctrl-C. Ctrl-C has to be pressed multiple times and all sorts of error messages appear on the screen.

How can you make a python script that uses multiprocessing and quits cleanly when it receives a Ctrl-C ?

Take this script for example

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)
役に立ちましたか?

解決 2

I believe the try-catch mentioned in a similar post here on SO could be adapted to cover it.

If you wrap the pool.map call in the try-catch and then call terminate and join I think that would do it.

[Edit]

Some experimentation suggests something along these lines works well:

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..'

I simplified your example somewhat to avoid having to load numpy on my machine to test but the critical part is the two try-except calls which handle the CTRL+C key presses.

他のヒント

Jon's solution is probably better, but here it is using a signal handler. I tried it in a VBox VM which was extremely slow, but worked. I hope it will help.

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)
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top