【30天玩转python】并发编程
并发编程
并发编程是指在同一时间处理多个任务的能力,任务可能是独立的,也可能是相互交错执行。并发编程的目标是充分利用 CPU 的多核处理能力,提升程序的执行效率。Python 提供了多种并发编程方法,包括多线程、多进程和异步编程。本文将介绍 Python 中的几种常见并发编程方式。
1. 多线程
多线程是一种常见的并发编程方式,它允许程序在同一进程中同时运行多个线程。Python 的 threading
模块提供了创建和管理线程的功能。
1.1 使用 threading
模块
通过 threading
模块可以轻松地创建和管理线程。下面是一个创建多线程的简单示例:
示例:创建多线程
import threading
import time
def worker(name):
print(f"线程 {name} 开始工作")
time.sleep(2)
print(f"线程 {name} 结束工作")
# 创建多个线程
threads = []
for i in range(3):
thread = threading.Thread(target=worker, args=(i,))
threads.append(thread)
thread.start()
# 等待所有线程完成
for thread in threads:
thread.join()
print("所有线程完成")
1.2 线程的同步
由于线程之间是并发执行的,所以需要确保对共享数据的访问是安全的。Python 提供了 Lock
(锁)机制来保证线程的同步。
示例:使用锁机制
import threading
counter = 0
lock = threading.Lock()
def increment():
global counter
with lock:
for _ in range(100000):
counter += 1
threads = []
for _ in range(2):
thread = threading.Thread(target=increment)
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
print(f"计数器值为: {counter}")
在这个示例中,使用 lock
来确保多个线程不会同时修改 counter
,避免竞态条件。
2. 多进程
多进程是一种并发编程方式,它通过在多个进程中运行任务来实现并发。每个进程都有自己的内存空间,因此多进程可以绕过 Python 中的全局解释器锁(GIL)限制,更适合 CPU 密集型任务。
2.1 使用 multiprocessing
模块
multiprocessing
模块用于创建和管理进程。与线程类似,进程可以并发执行任务,但进程之间的数据是独立的,无法直接共享。
示例:创建多进程
import multiprocessing
import time
def worker(name):
print(f"进程 {name} 开始工作")
time.sleep(2)
print(f"进程 {name} 结束工作")
if __name__ == "__main__":
processes = []
for i in range(3):
process = multiprocessing.Process(target=worker, args=(i,))
processes.append(process)
process.start()
for process in processes:
process.join()
print("所有进程完成")
2.2 进程间通信
由于进程之间的数据是独立的,Python 提供了 Queue
、Pipe
等机制来实现进程间通信(IPC,Inter-Process Communication)。
示例:使用 Queue
进行进程间通信
import multiprocessing
def worker(q):
q.put("任务完成")
if __name__ == "__main__":
queue = multiprocessing.Queue()
process = multiprocessing.Process(target=worker, args=(queue,))
process.start()
process.join()
# 从队列中获取结果
result = queue.get()
print(result)
在这个例子中,进程 worker
将结果放入队列中,主进程通过队列获取该结果。
3. 异步编程
异步编程是一种非阻塞的并发编程方式,适合 I/O 密集型任务。异步编程的核心思想是当一个任务等待 I/O 操作时,其他任务可以继续执行,从而避免阻塞。
3.1 使用 asyncio
模块
Python 的 asyncio
模块用于编写异步程序,通过 async
和 await
关键字定义异步函数。
示例:简单的异步函数
import asyncio
async def worker(name):
print(f"任务 {name} 开始")
await asyncio.sleep(2)
print(f"任务 {name} 结束")
async def main():
tasks = [worker(i) for i in range(3)]
await asyncio.gather(*tasks)
# 运行异步任务
asyncio.run(main())
在这个例子中,worker
是一个异步函数,它在执行 await asyncio.sleep(2)
时不会阻塞其他任务。
3.2 异步 I/O 操作
异步编程特别适合 I/O 密集型任务,比如网络请求、文件读写等。
示例:异步网络请求
import asyncio
import aiohttp
async def fetch(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
async def main():
urls = ['https://example.com', 'https://example.org']
tasks = [fetch(url) for url in urls]
results = await asyncio.gather(*tasks)
for result in results:
print(result)
# 运行异步任务
asyncio.run(main())
在这个示例中,使用 aiohttp
库进行异步网络请求,实现了非阻塞的 I/O 操作。
4. 协程与生成器
Python 的生成器(generator
)和协程(coroutine
)也是实现并发的工具之一。协程可以通过 yield
关键字暂停和恢复函数的执行。
4.1 协程示例
协程是一种比普通生成器更高级的函数控制机制,可以通过 yield
暂停执行,再通过 send()
恢复执行。
示例:协程
def coroutine_example():
print("启动协程")
result = yield
print(f"接收到的值: {result}")
co = coroutine_example()
next(co) # 启动协程
co.send(42) # 向协程发送值
在这个例子中,协程通过 yield
暂停执行,再通过 send()
传递数据并恢复执行。
5. 小结
并发编程在提升程序性能和响应速度方面具有重要作用。Python 提供了多种并发编程模型,包括多线程、多进程和异步编程。选择哪种模型取决于任务的特点:对于 I/O 密集型任务,异步编程是首选;对于 CPU 密集型任务,多进程可能表现更好;多线程适合轻量级的并发任务。理解并掌握这些并发编程模型,能够显著提升 Python 程序的执行效率。