python - 如何使用 ProcessPoolExecutor 优雅地退出程序?

标签 python python-3.x python-asyncio

以下面的程序为例:

import asyncio
from concurrent.futures import ProcessPoolExecutor


def process():
    print('processed')

async def main(loop, executor):
    await loop.run_in_executor(executor, process)
    await asyncio.sleep(60.0)

executor = ProcessPoolExecutor()
loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(main(loop, executor))
except KeyboardInterrupt:
    pass
finally:
    executor.shutdown()

如果我在程序运行时按 Ctrl + C,我会在程序退出时收到一条真正的消息回溯:

processed
^CProcess Process-3:
Process Process-4:
Process Process-2:
Traceback (most recent call last):
  File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/pytho
n3.5/multiprocessing/process.py", line 254, in _bootstrap
    self.run()
  File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/pytho
n3.5/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/pytho
n3.5/concurrent/futures/process.py", line 169, in _process_worker
    call_item = call_queue.get(block=True)
  File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/pytho
n3.5/multiprocessing/queues.py", line 93, in get
    with self._rlock:
  File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/pytho
n3.5/multiprocessing/synchronize.py", line 96, in __enter__
    return self._semlock.__enter__()
Traceback (most recentTraceback (most recent call last):
  File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/pytho
n3.5/multiprocessing/process.py", line 254, in _bootstrap
    self.run()
  File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/pytho
n3.5/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/pytho
n3.5/concurrent/futures/process.py", line 169, in _process_worker
    call_item = call_queue.get(block=True)
  File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/pytho
n3.5/multiprocessing/queues.py", line 94, in get
    res = self._recv_bytes()
  File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/pytho
n3.5/multiprocessing/connection.py", line 216, in recv_bytes
    buf = self._recv_bytes(maxlength)
  File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versi call last):
  File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/pytho
n3.5/multiprocessing/process.py", line 254, in _bootstrap
    self.run()
  File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/pytho
n3.5/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/pytho
n3.5/concurrent/futures/process.py", line 169, in _process_worker
    call_item = call_queue.get(block=True)
  File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/pytho
n3.5/multiprocessing/queues.py", line 93, in get
    with self._rlock:
  File "/usr/local/Cellar/python3/3.5.0/Frameworks/Python.framework/Versions/3.5/lib/pytho
n3.5/multiprocessing/synchronize.py", line 96, in __enter__
    return self._semlock.__enter__()
KeyboardInterrupt
..... (It goes on for a while longer)

在使用多处理池的程序中,是否有更优雅的方式来处理 KeyboardInterrupt

最佳答案

不确定这是否是正确(或唯一)的解决方案,但我通常会添加一个显式的 SIGINT 信号处理程序,而不是依赖于 KeyboardInterrupt 的默认行为由解释器在 SIGINT 上引发。这给了你更多的控制权,并希望避免意外的影响。

根据@germn 的建议更新:

import asyncio
import signal
from concurrent.futures import ProcessPoolExecutor

def shutdown(loop, executor):
    executor.shutdown()
    for task in asyncio.Task.all_tasks():
        task.cancel()
    loop.stop()

def process():
    print('processed')

async def main(loop, executor):
    await loop.run_in_executor(executor, process)
    loop.create_task(asyncio.sleep(120))
    loop.create_task(asyncio.sleep(12))
    loop.create_task(asyncio.sleep(130))
    await asyncio.sleep(60.0)

executor = ProcessPoolExecutor()
loop = asyncio.get_event_loop()
loop.add_signal_handler(signal.SIGINT, shutdown, loop, executor)
loop.run_until_complete(main(loop, executor))
loop.close()

关于python - 如何使用 ProcessPoolExecutor 优雅地退出程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33398933/

相关文章:

python - Python 2 的 "backporting"Python 3's ` range` 是个坏主意吗?

python - PCA无法在散点图上获取颜色

python map函数迭代

python-3.x - 无效的int()的Python文字,基数为: 'N' Error为10

python - 如何根据条件创建新列?

python-3.x - 尽管在预测过程中存在明显的错误分类,为什么我的检测分数仍然很高?

python - 如何修复 2 位数总和的 python 代码中的 ValueError?

python - 异步初始化时将参数传递给 python 类

python - 为什么 aiohttp 比 gevent 慢得可怕?

python - View 中的 Django asyncio 调用不起作用