Python 3.x 生成器函数,导致在所有进程完成后捕获异常

Python 3.x 生成器函数,导致在所有进程完成后捕获异常,python-3.x,iterator,multiprocessing,generator,itertools,Python 3.x,Iterator,Multiprocessing,Generator,Itertools,我写这篇简短的POC是为了帮助理解我遇到的问题,希望有人能向我解释发生了什么,以及我如何修复它和/或使它更有效 我使用迭代器、itertools和生成器的目标是因为我不想在内存中存储一个巨大的列表,因为我放大列表会变得难以管理,我不想每次都要循环整个列表来做一些事情。请注意,我对生成器、迭代器和多处理的概念还比较陌生,今天就编写了这段代码,因此,如果您能清楚地告诉我,我不理解这些东西如何工作的工作流,请教育我并帮助我改进代码 您应该能够按原样运行代码,并看到我面临的问题。我期待着一旦捕获到异常,

我写这篇简短的POC是为了帮助理解我遇到的问题,希望有人能向我解释发生了什么,以及我如何修复它和/或使它更有效

我使用迭代器、itertools和生成器的目标是因为我不想在内存中存储一个巨大的列表,因为我放大列表会变得难以管理,我不想每次都要循环整个列表来做一些事情。请注意,我对生成器、迭代器和多处理的概念还比较陌生,今天就编写了这段代码,因此,如果您能清楚地告诉我,我不理解这些东西如何工作的工作流,请教育我并帮助我改进代码

您应该能够按原样运行代码,并看到我面临的问题。我期待着一旦捕获到异常,它就会被引发,脚本就会死掉,但我看到的是,异常被捕获,但其他进程仍在继续

如果我注释掉
generateRange
generator并创建一个虚拟列表,并将其传递到
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

不可能立即取消运行futures,但这至少使其在引发异常后只运行几个进程:

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()                                                                 

您想要并行化的东西主要受CPU速度还是I/O的限制?如果是后者,多处理不是一个好主意-(如果它真的是prime detection,您将不得不使用多处理。如果它是I/O,我会推荐;它是极少数能够正确处理异常的并发解决方案之一。这只是一个POC,而不是我在@L3viathan实际执行的操作。不可能取消这样运行的进程。您可以做的是迭代
child
.cancel()
都包含期货,但还是会执行一些进程。虽然不是完整的80。注释是关键,尽管我以前有过注释,但在这里似乎很有效,很好的触摸,谢谢。