Reputation: 2170
I am using Ubuntu 16.04.2 LTS and Python 3.5.2.
I have a ThreadPool
from multiprocessing
doing some work.
Now I want to terminate this pool while doing its work.
Using ThreadPool.terminate()
does not work as expected.
When running the following example, the worker never stops doing its work and the program never runs past the ThreadPool.join()
call.
import time
from multiprocessing.pool import ThreadPool
def task():
try:
while True:
print("Working")
time.sleep(1)
except: # Unsuccessful attempt. :(
print("Working, stopping now")
thread_pool = ThreadPool(processes=1)
thread_pool.apply_async(task)
time.sleep(1) # Make sure the task is actually started.
print("Terminating")
thread_pool.terminate()
print("Termination: Initiated")
thread_pool.join() # Does not return.
print("Termination: Done")
What am I doing wrong?
Upvotes: 0
Views: 3365
Reputation: 488163
You specifically requested a ThreadPool
rather than a Pool
. This means that instead of creating a new process, the multiprocessing
code will create a local thread (in your own process).
A ThreadPool
instance cannot be terminated abruptly as there is no defined mechanism for that (vs a process, where the system can call os.kill
). In your code, the .terminate
directive winds up being ignored. In fact, it sets a flag that the pool instance would check when the task returns, but your task never returns. We can see this with a revised version:
import argparse
import sys
import time
from multiprocessing.pool import Pool, ThreadPool
def task(arg):
for i in range(3):
print("Working on", arg, "with i =", i)
time.sleep(1)
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--delay', default=1, type=float)
args = parser.parse_args()
thread_pool = ThreadPool(processes=1)
thread_pool.apply_async(task, (0,))
thread_pool.apply_async(task, (1,))
time.sleep(args.delay)
print("Terminating")
thread_pool.terminate()
print("Termination: Initiated")
thread_pool.join() # Does not return.
print("Termination: Done")
if __name__ == '__main__':
try:
sys.exit(main())
except KeyboardInterrupt:
sys.exit('\nInterrupted')
which does this when run with no arguments:
$ python3 tp.py
Working on 0 with i = 0
Working on 0 with i = 1
Terminating
Termination: Initiated
Working on 0 with i = 2
Termination: Done
and this when run with --delay 5
:
$ python3 tp.py --delay 5
Working on 0 with i = 0
Working on 0 with i = 1
Working on 0 with i = 2
Working on 1 with i = 0
Working on 1 with i = 1
Terminating
Working on 1 with i = 2
Termination: Initiated
Termination: Done
Alternatively, if you just use a Pool
instead of a ThreadPool
, you will get a real process and can use .terminate
on it at any time (modulo the usual caveats about screwing up communications queues).
Upvotes: 1