本文共 3245 字,大约阅读时间需要 10 分钟。
多线程与并发编程是现代软件开发中的核心技能之一,特别是在处理I/O密集型任务、网络请求、数据库操作等场景中,多线程可以显著提升性能。本文将从基础到高级探讨Python中的多线程与协程编程知识。
线程是操作系统任务调度的基本单元,具有以下特点:
GIL(Global Interpreter Lock)是Python解释器的关键机制,保证了在多线程环境下Python程序的正确执行。GIL通过锁机制实现线程间的互斥,确保在同一时刻只有一个线程执行Python代码。
在多线程环境中,共享资源可能引发竞争和并发访问问题。为了保证线程安全,通常需要使用同步锁(如threading.Lock)和互斥机制。
锁用于保护共享资源,确保在多线程环境下资源只能被一个线程占用。常见类型包括:
threading.Lock):基于GIL实现的粗粒度锁。threading.RLock):支持多次递归使用,适合递归函数。import threadinglock = threading.Lock()lock.acquire() # 加锁try: # 执行共享资源操作 print("获取锁成功")finally: lock.release() # 释放锁 死锁是多个线程因争夺资源而无法继续执行的状态。常见原因包括:
lock.acquire()和lock.release()互相等待)。递归锁通过计数器机制支持多次锁使用,适合递归函数。
import threadingrlock = threading.RLock()rlock.acquire()try: # 使用递归锁 print("获取递归锁成功")finally: rlock.release() Event对象用于线程间的同步和通信,通过设置和等待信号标志来控制线程的执行。
import threadingimport timeevent = threading.Event()t1 = threading.Thread(target=lambda: event.wait(2))t1.start()time.sleep(6)event.set()
Event适用于需要等待外部条件的场景,如等待Redis服务启动或数据库连接成功。
信号量通过计数器管理资源访问次数,限制最大连接数或并发使用数量。
import threadingimport timefrom threading import Semaphoresemaphore = Semaphore(5)def func(): if semaphore.acquire(): print(threading.current_thread().name + "获取信号量") time.sleep(2) semaphore.release()for _ in range(20): t = threading.Thread(target=func) t.start()
信号量常用于限制资源连接数,如数据库连接池或服务器入口。
Python提供三种队列实现:
queue.Queue:FIFO,先进先出。queue.LifoQueue:LIFO,先进后出。queue.PriorityQueue:优先级队列,先进最小。import queueq = queue.Queue()q.put(1)q.put(2)print(q.qsize()) # 2msg = q.get()print("获取:", msg) 生产者将数据写入队列,消费者从队列中读取数据,通过队列实现资源的松耦合。
使用multiprocessing.Process创建进程,适用于需要充分利用多核资源的任务。
import multiprocessingdef func(): print("hello")p = multiprocessing.Process(target=func)p.start()p.join() 支持进程的启动、join、terminate等操作,以及进程间的互斥锁、Event、Semaphore等同步机制。
import timedef consumer(): r = '' while True: n = yield r if not n: break print(f"CONSUMER: 消耗{ n }...") time.sleep(1) r = "200 OK"produce = consumer()for i in range(5): produce.send(i) greenlet是协程的基础库,gevent提供了更高级别的API,支持并发网络操作。
from gevent import monkey, sleepmonkey.patch_all()def f(url): print(f"GET: {url}") resp = request.urlopen(url) data = resp.read() print(f"{len(data)} bytes received from {url}")gevent.joinall([ gevent.spawn(f, 'https://itk.org/'), gevent.spawn(f, 'https://www.github.com/'), gevent.spawn(f, 'https://zhihu.com/'),]) GIL是Python解释器层面的锁机制,粗粒度锁(如threading.Lock)和细粒度锁(如threading.RLock)共同保障线程安全。
信号量用于控制资源访问次数,队列用于数据传输和缓冲,两者配合使用常见于生产者-消费者模式。
多线程与协程编程是提升Python应用性能的关键技术。通过合理使用锁、Event、信号量、队列等同步机制,可以在多核环境下充分发挥性能潜力。选择多线程还是多进程或协程,需根据任务特性和资源需求进行权衡。
转载地址:http://soofk.baihongyu.com/