如何在执行as_completed前等待ProcessPoolExecutor所有任务完成?
问题分析与解决方案
错误根源
你代码里的executor.submit(...).result()是核心问题:.result()会立即阻塞当前线程,直到该任务执行完毕并返回结果。这导致future变量存储的是任务的执行结果(比如找到的密码或None),而非Future对象。而as_completed()需要接收Future对象集合,自然会报AttributeError——因为None没有_condition属性。
快速任务(比如列表相乘)看似正常,是因为任务瞬间完成,.result()立即返回结果,这时候你误把结果当Future用,但快速任务的结果可能刚好不是None,或者没触发as_completed里的检查,但本质逻辑是错误的,只是没暴露问题而已。
解决方案
1. 修正核心逻辑(保留as_completed的提前终止优势)
去掉.result(),直接将Future对象存入字典,让as_completed正常工作。这样一旦有任务找到密码,就能立即停止所有任务,符合暴力破解的效率需求:
def main(): start_time = time() cpu_cores = os.cpu_count() - LIMIT part_size = len(CHARACTERS)//cpu_cores password = None # 提前初始化password变量,避免未定义报错 for length in range(MAX_LENGTH): with Manager() as manager: event = manager.Event() with ProcessPoolExecutor() as executor: attacks = {} for part in range(cpu_cores): if part == cpu_cores - 1: first_bit = CHARACTERS[part_size * part :] else: first_bit = CHARACTERS[part_size * part : part_size * (part+1)] # 关键修改:去掉.result(),直接存Future对象 future = executor.submit(brute_force, SECRET_STRING, first_bit, event, *([CHARACTERS] * length)) attacks[future] = f"Brute Force {length} - {first_bit}" for attack in as_completed(attacks): try: password = attack.result() except Exception as e: print(f"任务执行出错: {e}") continue if password: attack_type = attacks[attack] print(f"Password found by {attack_type} attack: {password}") event.set() break if password: break print(f"Password not found on length of {length}") end_time = time() duration = end_time - start_time print(f"Total execution time: {duration:.5f} seconds\n")
2. 如果确实需要等待所有任务完成再处理
如果你不需要提前终止,一定要等所有任务跑完再处理结果,可以用executor.shutdown(wait=True)或者concurrent.futures.wait(),但这样会浪费暴力破解的效率:
# 替换as_completed的部分代码 import concurrent.futures futures = list(attacks.keys()) # 等待所有任务完成 concurrent.futures.wait(futures) # 遍历所有任务结果 for future in futures: password = future.result() if password: attack_type = attacks[future] print(f"Password found by {attack_type} attack: {password}") break
补充说明
- 暴力破解场景下,优先用第一种方案:一旦找到密码就触发
event.set(),让其他任务检测到事件后提前退出,节省资源。 - 注意提前初始化
password变量,避免循环外引用未定义变量的报错。 - 建议给
result()加上异常捕获,避免单个任务出错导致整个程序崩溃。
内容的提问来源于stack exchange,提问作者Almus
相关产品推荐
相关产品推荐

