python处理多并发
python处理多并发
在python中实现多并发可以通过多线程,多进程或者异步I/O方式实现,各种方法适合的应用场景不同,具体选择取决于你的任务类型和资源需求
多线程
多线程适合于I/O密集型任务,因为线程相对轻量,可以方便地切换来优化等待时间
import threading
def worker(num):
print(f'Thread {num} is running')
threads = []
for i in range(5):
thread = threading.Thread(target=worker, args=(i,))
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
多进程
多进程适用于cpu密集型任务,因为每个进程被分配独立的内存空间,能充分利用多核 CPU 的优势。
from multiprocessing import Process
def worker(num):
print(f'Process {num} is running')
processes = []
for i in range(5):
process = Process(target=worker, args=(i,))
processes.append(process)
process.start()
for process in processes:
process.join()
异步 I/O
异步 I/O 非常适合大量 I/O 操作,如访问网络、文件读取等,能够在等待 I/O 完成时执行其他任务。
import asyncio
async def worker(num):
print(f'Worker {num} is starting')
await asyncio.sleep(2) # 模拟 I/O 操作
print(f'Worker {num} finished')
async def main():
tasks = [worker(i) for i in range(5)]
await asyncio.gather(*tasks)
asyncio.run(main())
选择合适的方法
- 多线程:适用于 I/O 密集型任务。注意 GIL(全局解释器锁)的影响,在 Python 中多线程不适合 CPU 密集型任务。
- 多进程:适用于 CPU 密集型任务,无需考虑 GIL,因为每个进程有独立的解释器实例。
- 异步 I/O:适用于网络请求、文件读写等异步操作,能够高效地处理大量 I/O 请求。
注意事项
- 在使用多线程和多进程时,注意共享资源的同步,以避免竞争条件。
- 异步编程可能需要额外考虑依赖库或代码结构的重构,以支持异步编程风格。
- 对于简单的任务,可以从线程开始,对于更复杂的任务则选择合适的并发模型。
线程资源同步
使用threading.Lock
threading.Lock
是最基础的锁机制。它可以用来确保某一时刻只有一个线程可以访问共享资源。
import threading
# 共享资源
shared_data = 0
# 锁对象
lock = threading.Lock()
def worker():
global shared_data
# 进入临界区
with lock:
# 操作共享资源
for _ in range(100000):
shared_data += 1
# 创建线程
threads = [threading.Thread(target=worker) for _ in range(5)]
# 启动线程
for thread in threads:
thread.start()
# 等待所有线程完成
for thread in threads:
thread.join()
print(f'Shared Data: {shared_data}')
在这个例子中,我们创建了多个线程,它们会同时尝试更新共享变量shared_data
.通过使用lock
,确保对于shared_data
的增量操作是原子的,即被完整执行的
使用threading.RLock
threading.RLock
是可重入锁,允许同一线程在不产生死锁的情况下多次获得锁。这在某个线程需要多次访问同一使用 Lock
保证同步的代码段时非常有用。
import threading
lock = threading.RLock()
def recursive_count(n):
with lock:
if n > 0:
print(n)
recursive_count(n - 1)
t = threading.Thread(target=recursive_count, args=(5,))
t.start()
t.join()
使用 threading.Condition
threading.Condition
允许线程等待某个条件发生。它实际上是 Lock
和 Events
的结合体,适用于更复杂的同步需求。
import threading
# 共享资源
shared_data = []
# 条件变量
condition = threading.Condition()
def producer():
global shared_data
with condition:
for i in range(5):
shared_data.append(i)
print(f'Produced {i}')
condition.notify() # 通知消费者
def consumer():
global shared_data
with condition:
while True:
condition.wait() # 等待生产者通知
item = shared_data.pop(0)
print(f'Consumed {item}')
if not shared_data:
break
# 启动生产者和消费者线程
t1 = threading.Thread(target=producer)
t2 = threading.Thread(target=consumer)
t1.start()
t2.start()
t1.join()
t2.join()
选择合适的同步机制
- 使用
Lock
来保护对共享资源的简洁访问。 - 使用
RLock
如果同一个线程需要多次进入锁定部分。 - 使用
Condition
处理复杂的状态和等待信号的场景。