Python多线程实现gather and go的正确方式及场景标准名称
问题解答
你的手写实现是否正确?
你给出的基于双Event(单工作线程就绪Event+全局放行Event)的实现是完全正确的,不存在竞态问题:
- 每个工作线程初始化完成后只会标记自己专属的就绪Event,不会和其他线程产生状态冲突
- 主线程遍历等待所有就绪Event被触发的逻辑,可以准确感知到全部工作线程就绪的时机
- 最后通过全局goEvent统一放行,能保证所有工作线程几乎同时开始执行后续逻辑
如果说优化点,仅在工作线程规模极大时,为每个线程单独创建Event会产生少量可忽略的内存开销,绝大多数业务场景下这个写法的可读性和可靠性都没有问题。
Python 内置的标准实现
Python标准库threading模块中已经提供了专门用于这类场景的工具:Barrier(屏障),不需要手动维护多组Event就可以实现完全一致的效果。Barrier在初始化时需要指定需要等待的参与方数量,还支持传入action回调:当所有参与方都到达屏障点时,会先由其中一个线程执行action回调,之后所有阻塞在屏障点的线程会被同时放行。
用Barrier改写后的代码如下:
from threading import Thread, Lock, current_thread, Barrier from datetime import datetime from time import sleep from random import random log_lock = Lock() def log(msg): with log_lock: print("{} ({}) {}".format(datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"), current_thread().name, msg)) def worker(barrier): log("Initializing worker") sleep(2 + random() * 3) log("Worker is ready") # 到达屏障点,等待其他线程 barrier.wait() log("Worker is working") log("Worker has finished their work") def main(): worker_count = 5 def all_ready_trigger(): log("All workers are ready, Go!") # 初始化屏障,等待5个工作线程全部到达 start_barrier = Barrier(worker_count, action=all_ready_trigger) for i in range(1, worker_count + 1): Thread(name=f"Worker-{i}", target=worker, args=(start_barrier,)).start() if __name__ == '__main__': main()
除了基础的等待放行能力,Barrier还支持超时等待、屏障重置、获取当前等待线程数等进阶能力,适配更复杂的同步需求。
该同步场景的专业名称
这类同步模式的标准专业称谓是屏障同步(Barrier Synchronization),是并发编程领域非常经典的同步原语使用场景,核心特征就是让一组执行单元(线程/进程/协程)在指定同步点等待,直到所有单元都抵达该点后再统一继续执行,和田径比赛中所有选手就位后再统一发令起跑的逻辑完全一致。
你提到的"gather and go"是非常形象的口语化描述,部分技术博客和社区讨论中也会使用,但正式文档和学术资料中统一使用屏障同步这一名称。
内容的提问来源于stack exchange,提问作者Vespene Gas
相关产品推荐
相关产品推荐

