案例 1:多线程售票 + 互斥锁(最经典)
作用
多个线程卖同一份票,不加锁会超卖、负数;加锁就安全。
importthreadingimporttime# 共享数据:总票数ticket=10# 创建互斥锁:保证同一时间只有一个线程修改票数lock=threading.Lock()defsale_ticket():globalticketwhileTrue:# 🔒 加锁:开始操作共享数据lock.acquire()try:ifticket>0:time.sleep(0.1)# 模拟出票延迟print(f"{threading.current_thread().name}卖出第{ticket}张票")ticket-=1# 修改共享数据else:print(f"{threading.current_thread().name}:票卖完了")breakfinally:# 🔓 解锁:必须释放,否则卡死lock.release()if__name__=="__main__":# 创建2个售票线程t1=threading.Thread(target=sale_ticket,name="窗口1")t2=threading.Thread(target=sale_ticket,name="窗口2")t1.start()t2.start()t1.join()t2.join()关键点讲解
ticket = 10:所有线程共享lock = threading.Lock():互斥锁lock.acquire():抢占锁,抢到才能执行lock.release():释放锁,别人才能用try...finally:保证无论是否出错,锁一定释放
案例 2:多进程(独立、隔离、不共享)
作用
演示进程有独立内存、独立 PID、互不影响。
importmultiprocessingimportosimporttimedefprocess_task(name):# 每个进程有自己的PIDprint(f"子进程{name}运行,PID ={os.getpid()}")time.sleep(0.5)print(f"子进程{name}结束")if__name__=="__main__":# 创建2个进程p1=multiprocessing.Process(target=process_task,args=("A",))p2=multiprocessing.Process(target=process_task,args=("B",))p1.start()# 启动p2.start()p1.join()# 等待结束p2.join()print("主进程结束")关键点讲解
- 每个进程有独立 PID
- 进程之间不共享变量
- Windows 必须写
if __name__ == "__main__" - 进程开销比线程大,但更稳定
案例 3:进程池 + Manager ().Queue 通信
作用
进程池里的进程必须用 Manager ().Queue 通信,普通 Queue 不能用。
importmultiprocessingfromconcurrent.futuresimportProcessPoolExecutorimporttimedefpool_task(q,i):# 往队列里放数据q.put(f"进程池任务{i}执行完毕")time.sleep(0.3)if__name__=="__main__":# 🚨 进程池通信必须用这个队列!q=multiprocessing.Manager().Queue()# 创建进程池,最多2个进程withProcessPoolExecutor(max_workers=2)aspool:foriinrange(3):pool.submit(pool_task,q,i)# 读取结果whilenotq.empty():print(q.get())关键点讲解
- 进程池通信 =Manager().Queue()
ProcessPoolExecutor:进程池submit(函数, 参数1, 参数2...):提交任务- 进程池自动管理进程创建 / 销毁
案例 4:线程池(工作最常用)
作用
批量处理 IO 任务(爬虫、文件、网络),高效、轻量。
fromconcurrent.futuresimportThreadPoolExecutorimporttimedefthread_task(i):time.sleep(0.2)returnf"线程池任务{i}完成"if__name__=="__main__":# 创建线程池,最多2个线程withThreadPoolExecutor(max_workers=2)asexecutor:# 批量提交任务results=executor.map(thread_task,[1,2,3])# 遍历结果forresinresults:print(res)关键点讲解
ThreadPoolExecutor:最推荐的多线程写法map(任务函数, 参数列表):一键批量提交- 自动管理线程,不用
start/join - 适合:IO 密集型(爬虫、文件、网络)
🔥 终极总结
线程共享数据 → 必须加锁
进程独立数据 → 通信要用 Queue
进程池通信 → 必须用 Manager ().Queue
IO 密集 → 线程池
CPU 密集 → 进程池
Windows 多进程 → 必须加 if *name*== “*main*”
""" @Author:zhuyahao @Time:2026/4/17 @Desc: """# ===================== 0. 导入模块 =====================importmultiprocessingimportthreadingfromconcurrent.futuresimportThreadPoolExecutor,ProcessPoolExecutorimporttimeimportos# ===================== 1. 多线程 + 互斥锁(售票) =====================ticket=10lock=threading.Lock()defsale_ticket():globalticketwhileTrue:lock.acquire()# 加锁try:ifticket>0:time.sleep(0.1)print(f"{threading.current_thread().name}卖出第{ticket}张票")ticket-=1else:print(f"{threading.current_thread().name}:票已卖完")breakfinally:lock.release()# 解锁# ===================== 2. 多进程(独立任务) =====================defprocess_task(name):print(f"子进程{name}运行,PID={os.getpid()}")time.sleep(0.5)returnf"进程{name}完成"# ===================== 3. 进程池 + Manager队列(通信) =====================defpool_task(q,i):q.put(f"进程池任务{i}完成")time.sleep(0.3)# ===================== 4. 线程池 =====================defthread_task(i):time.sleep(0.2)returnf"线程池任务{i}完成"# ===================== 主程序入口(Windows必须) =====================if__name__=="__main__":print("====== 1. 多线程售票(锁)======")t1=threading.Thread(target=sale_ticket,name="窗口1")t2=threading.Thread(target=sale_ticket,name="窗口2")t1.start()t2.start()t1.join()t2.join()print("\n====== 2. 多进程 =====")p1=multiprocessing.Process(target=process_task,args=("A",))p2=multiprocessing.Process(target=process_task,args=("B",))p1.start()p2.start()p1.join()p2.join()print("\n====== 3. 进程池 + 通信 =====")q=multiprocessing.Manager().Queue()withProcessPoolExecutor(2)aspool:foriinrange(10):pool.submit(pool_task,q,i)whilenotq.empty():print(q.get())print("\n====== 4. 线程池 =====")withThreadPoolExecutor(2)asexecutor:results=executor.map(thread_task,[1,2,3])forresinresults:print(res)print("\n✅ 全部运行完成!")======1.多线程售票(锁)======窗口1卖出第10张票 窗口2卖出第9张票 窗口2卖出第8张票 窗口2卖出第7张票 窗口2卖出第6张票 窗口2卖出第5张票 窗口2卖出第4张票 窗口2卖出第3张票 窗口1卖出第2张票 窗口2卖出第1张票 窗口1:票已卖完 窗口2:票已卖完======2.多进程=====子进程 A 运行,PID=4400子进程 B 运行,PID=32036======3.进程池+通信=====进程池任务0完成 进程池任务1完成 进程池任务2完成 进程池任务3完成 进程池任务4完成 进程池任务5完成 进程池任务6完成 进程池任务7完成 进程池任务8完成 进程池任务9完成======4.线程池=====线程池任务1完成 线程池任务2完成 线程池任务3完成 ✅ 全部运行完成! 进程已结束,退出代码为0