简体   繁体   English

如何停止 ThreadPoolExecutor.map 并在 CTRL-C 上退出?

[英]How to stop ThreadPoolExecutor.map and exit on CTRL-C?

A python script executes an IO-bound function a lot of times (order of magnitude: anything between 5000 and 75000). python 脚本会多次执行 IO 绑定函数(数量级:5000 到 75000 之间的任何值)。 This is still pretty performant by using通过使用,这仍然非常高效

def _iterator(): ...  # yields 5000-75000 different names
def _thread_function(name): ...

with concurrent.futures.ThreadPoolExecutor(max_workers=11) as executor:
    executor.map(_thread_function, _iterator(), timeout=44)

If a user presses CTRL-C, it just messes up a single thread.如果用户按下 CTRL-C,它只会弄乱一个线程。 I want it to stop launching new threads;我希望它停止启动新线程; and finish the current ongoing threads or kill them instantly, whatever.并完成当前正在进行的线程或立即杀死它们,无论如何。

How can I do that?我怎样才能做到这一点?

Exception handling in concurrent.futures.Executor.map might answer your question. concurrent.futures.Executor.map 中的异常处理可能会回答您的问题。

In essence, from the documentation of concurrent.futures.Executor.map本质上,来自concurrent.futures.Executor.map的文档

If a func call raises an exception, then that exception will be raised when its value is retrieved from the iterator.如果 func 调用引发异常,则在从迭代器检索其值时将引发该异常。

As you are never retrieving the values from map(), the exception is never raised in your main thread.由于您永远不会从 map() 检索值,因此您的主线程中永远不会引发异常。

Furthermore, from PEP 255此外,来自PEP 255

If an unhandled exception-- including, but not limited to, StopIteration --is raised by, or passes through, a generator function, then the exception is passed on to the caller in the usual way, and subsequent attempts to resume the generator function raise StopIteration.如果未处理的异常——包括但不限于 StopIteration——由生成器函数引发或通过,则异常以通常的方式传递给调用者,并随后尝试恢复生成器函数引发停止迭代。 In other words, an unhandled exception terminates a generator's useful life.换句话说,未处理的异常会终止生成器的使用寿命。

Hence if you change your code to (notice the for loop):因此,如果您将代码更改为(注意for循环):

def _iterator(): ...  # yields 5000-75000 different names
def _thread_function(name): ...

with concurrent.futures.ThreadPoolExecutor(max_workers=11) as executor:
    for _ in executor.map(_thread_function, _iterator(), timeout=44):
        pass

The InterruptedError will be raised in the main thread, and by passing through the generator ( executor.map(_thread_function, _iterator(), timeout=44) ) it will terminate it. InterruptedError将在主线程中引发,并通过生成器( executor.map(_thread_function, _iterator(), timeout=44) )将终止它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM