我写了这个简短的POC来帮助理解我遇到的问题,希望有人可以向我解释发生了什么,以及如何解决和/或提高效率。
我使用迭代器,itertools和生成器的目的是因为我不想在内存中存储一个巨大的列表,因为按比例放大列表将变得难以管理,并且我不想遍历整个列表每一次做某事。请注意,我对生成器,迭代器和多处理的想法还很陌生,并且今天就编写了这段代码,因此,如果您可以清楚地告诉我我想念工作流中这些东西是如何工作的,请怀念我,并帮助我代码更好。
您应该能够按原样运行代码,并查看我面临的问题。我正在期待,一旦捕获到异常,它就被引发并且脚本死了,但是我所看到的正在发生,捕获了异常,但其他过程仍在继续。
如果我注释掉generateRange
生成器并创建一个虚拟列表并将其传递给futures = (map(executor.submit, itertools.repeat(execute), mylist))
,则会捕获到异常并按预期退出脚本。
我的猜测是,生成器/迭代器必须在脚本死之前完成生成范围,据我所知,情况并非如此。
我之所以选择使用生成器函数/迭代器是因为您只能在需要它们时才能访问它们。
有没有办法让我停止生成器继续运行,并适当地引发异常。
这是我的POC:
import concurrent.futures
PRIMES = [0]*80
import time
def is_prime(n):
print("Enter")
time.sleep(5)
print("End")
1/0
child = []
def main():
with concurrent.futures.ProcessPoolExecutor(max_workers=1) as executor:
for i in PRIMES:
child.append(executor.submit(is_prime, i))
for future in concurrent.futures.as_completed(child):
if future.exception() is not None:
print("Throw an exception")
raise future.exception()
if __name__ == '__main__':
main()
编辑:我用更简单的方法更新了POC。
答案 0 :(得分:1)
不可能立即取消正在运行的期货,但这至少可以做到,因此在引发异常之后仅运行少数几个进程:
import concurrent.futures
PRIMES = [0]*80
import time
def is_prime(n):
print("Enter")
time.sleep(5)
print("End")
1/0
child = []
def main():
with concurrent.futures.ProcessPoolExecutor(max_workers=1) as executor:
for i in PRIMES:
child.append(executor.submit(is_prime, i))
for future in concurrent.futures.as_completed(child):
if future.exception() is not None:
for fut in child:
fut.cancel()
print("Throw an exception")
raise future.exception()
if __name__ == '__main__':
main()