
目录前言多进程fork仅Linux/macOSmultiprocessing 跨平台多进程推荐Pool进程池进程间通信 Queue多线程基础线程示例线程锁 LockGIL全局解释器锁ThreadLocal进程 VS 线程分布式进程小结前言现代操作系统都支持多任务。进程、线程是操作系统实现多任务的基础单位。进程操作系统资源分配的最小单位线程进程内调度执行的最小单位 一个进程至少包含一个主线程同一个进程内的多个线程共享该进程的内存资源。 Python中提供multiprocessing实现多进程、threading实现多线程同时有GIL全局解释器锁这个重要限制。多进程Python的os.fork()在Linux/macOS可用Windows不支持跨平台推荐使用multiprocessing模块。fork仅Linux/macOS调用fork()时操作系统把当前进程复制一份分出子进程返回0代表子进程返回子进程PID代表父进程import os pid os.fork() if pid 0: print(f我是子进程pid{os.getpid()}, 父进程pid{os.getppid()}) else: print(f我是父进程pid{os.getpid()}, 创建子进程pid{pid})multiprocessing 跨平台多进程推荐from multiprocessing import Process import os def run_proc(name): print(f子进程 {name} pid{os.getpid()}, 父pid{os.getppid()}) if __name__ __main__: print(f主进程pid{os.getpid()}) p Process(targetrun_proc, args(test,)) print(准备启动子进程) p.start() p.join() # 等待子进程执行完毕主进程再往下走 print(子进程结束)start()启动进程join()阻塞等待子进程结束常用于同步Windows必须写if __name__ __main__防止递归创建子进程Pool进程池批量创建大量子进程复用进程减少创建销毁开销from multiprocessing import Pool import os, time def long_task(x): print(f执行任务 {x}, pid{os.getpid()}) time.sleep(1) return x*x if __name__ __main__: p Pool(4) # 最多同时4个进程 res p.map(long_task, range(5)) print(res) p.close() p.join()进程间通信 Queue进程之间内存隔离不能直接共享变量用Queue传递消息from multiprocessing import Process, Queue def write(q): for val in [A,B,C]: q.put(val) def read(q): while True: v q.get() print(读到, v) if __name__ __main__: q Queue() pw Process(targetwrite, args(q,)) pr Process(targetread, args(q,)) pw.start() pr.start() pw.join() pr.terminate()多线程Python线程由threading模块封装底层调用操作系统原生线程。 线程共享当前进程的内存空间所以全局变量可以在线程之间直接访问容易出现竞争需要加锁。基础线程示例import threading, time def loop(): print(f子线程 {threading.current_thread().name} 启动) time.sleep(1) print(f子线程 {threading.current_thread().name} 结束) print(f主线程 {threading.current_thread().name}) t threading.Thread(targetloop, nameLoopThread) t.start() t.join() print(主线程结束)线程锁 Lock多个线程修改同一个共享变量会出现数据错乱竞态条件需要互斥锁import threading balance 0 lock threading.Lock() def change(n): global balance lock.acquire() try: balance n finally: lock.release() # 一定要释放锁防止死锁 t1 threading.Thread(targetchange, args(5,)) t2 threading.Thread(targetchange, args(-5,)) t1.start() t2.start() t1.join() t2.join() print(balance)注意锁会让并发变成串行降低速度不要持有锁太久避免死锁。GIL全局解释器锁CPython存在GIL同一时刻一个进程内只有一个线程在执行Python字节码。 所以CPU密集型任务多线程无法利用多核效率差优先用多进程IO密集型任务网络、文件读写、sleep多线程适合IO阻塞时释放GIL并发效果好ThreadLocal同一个进程内线程共享变量加锁麻烦ThreadLocal用来保存线程独有的局部变量每个线程读写自己那一份副本互不干扰不用加锁。import threading local_school threading.local() def process_student(): std local_school.student print(f线程 {threading.current_thread().name} 中的学生{std}) def process_thread(name): local_school.student name process_student() t1 threading.Thread(targetprocess_thread, args(小明,), nameThread-A) t2 threading.Thread(targetprocess_thread, args(小红,), nameThread-B) t1.start() t2.start() t1.join() t2.join()简单理解ThreadLocal像一个字典key自动绑定当前线程每个线程只能读到自己存的数据。进程 VS 线程对比项进程线程资源独立内存空间资源隔离共享所属进程内存资源共享开销创建、切换开销大轻量切换开销小通信隔离必须Queue、Pipe等通信直接读写共享变量需要锁稳定性一个进程崩溃不影响其他进程一个线程崩溃会导致整个进程崩溃多核利用不受GIL限制可以充分利用多核CPUCPython受GIL限制CPU密集无法并行选型口诀CPU密集型计算优先多进程利用多核IO密集网络请求、文件读写优先多线程/协程开销更小分布式进程multiprocessing.managers支持把Queue放到网络上实现跨机器的分布式进程。 一台机器作为服务端把队列注册到网络其他机器作为客户端连接这个队列收发任务实现分布式任务调度。服务端代码任务分发from multiprocessing.managers import BaseManager task_queue Queue() result_queue Queue() class QueueManager(BaseManager): pass QueueManager.register(get_task_queue, callablelambda: task_queue) QueueManager.register(get_result_queue, callablelambda: result_queue) manager QueueManager(address(, 5000), authkeybabc) manager.start() task manager.get_task_queue() result manager.get_result_queue() # 放任务 for i in range(5): task.put(i) # 接收结果 for _ in range(5): print(结果, result.get()) manager.shutdown()客户端代码工作节点from multiprocessing.managers import BaseManager class QueueManager(BaseManager): pass QueueManager.register(get_task_queue) QueueManager.register(get_result_queue) server_addr 127.0.0.1 m QueueManager(address(server_addr, 5000), authkeybabc) m.connect() task m.get_task_queue() result m.get_result_queue() for _ in range(5): n task.get() print(f计算 {n}*{n}) result.put(n*n)注意分布式进程底层走网络适合简单分布式任务生产一般用Celery这类成熟任务框架。小结多进程multiprocessing跨平台进程间隔离Queue通信适合CPU密集多线程threading共享内存修改共享变量必须加Lock适合IO密集ThreadLocal存放线程私有数据免除锁的麻烦GIL是CPython的特点是选择进程/线程的核心依据分布式进程借助managers把队列暴露到网络实现跨主机任务分发。