Python 并发编程是指在同一时间段内同时处理多个任务的编程方式。并发编程可以加速程序的执行速度,特别是在处理 I/O 密集型任务(如文件操作、网络请求等)时,能够更有效地利用系统资源。Python 提供了多种并发编程的方式,包括多线程、多进程、协程等。
线程与进程:
使用场景:
多线程实现:
Python的threading
模块提供了线程创建和管理的功能。
import threading
def print_numbers():
for i in range(5):
print(i)
# 创建线程
thread1 = threading.Thread(target=print_numbers)
thread2 = threading.Thread(target=print_numbers)
# 启动线程
thread1.start()
thread2.start()
# 等待线程结束
thread1.join()
thread2.join()
print("Threads finished executing")
GIL(全局解释器锁):
线程安全:
在多线程环境中,共享数据可能会导致数据冲突,需要通过加锁来确保数据安全。
Lock = threading.Lock()
Lock = threading.RLock()
使用示例:
import threading
lock = threading.Lock()
counter = 0
def increment():
global counter
with lock:
counter += 1
threads = [threading.Thread(target=increment) for _ in range(100)]
for thread in threads:
thread.start()
for thread in threads:
thread.join()
print(counter) # 预期输出 100
线程池:
线程池可以限制线程数量,避免线程过多导致的资源浪费。
import time
import random
from concurrent.futures import ThreadPoolExecutor
def task(url):
print(f"开始执行任务 {url}")
time.sleep(5)
return random.randint(0, 10)
def done(response):
print(f"根据task的结果,执行done {response.result()}")
# 创建线程池,最多维护10个线程。
pool = ThreadPoolExecutor(10)
url_list = [f"www.example.com/{i}" for i in range(300)]
future_list = []
for url in url_list:
future = pool.submit(task, url)
future.add_done_callback(done) # 回调,任务完成后执行done
future_list.append(future) # 存储任务结果
pool.shutdown(wait=True) # 等待所有任务执行完毕
for fut in future_list:
print(fut.result())
print("END")
单例模式:
在类的实例化过程中,希望使用单例模式,即创建对象时,始终使用最开始创建的那个,这样可以确保所有实例都指向同一个对象(地址相同,且共用变量)
import threading
class Singleton:
instance = None
lock = threading.RLock()
def __init__(self, name):
self.name = name
@classmethod
def _new__(cls, *args, **kwargs):
with cls.lock:
if cls.instance is None:
cls.instance = object.__new__(cls)
return cls.instance
obj1 = Singleton('alex') # 当obj1创建时,初始化了instance
obj2 = Singleton('alex') # 当obj2创建时,由于instance已经被创建,此时不会再次创建
进程与进程间通信:
Queue
、Pipe
等)来交换数据。多进程实现:
Python的multiprocessing
模块提供了创建和管理进程的功能。
import multiprocessing
def print_numbers():
for i in range(5):
print(i)
# 创建进程
process1 = multiprocessing.Process(target=print_numbers)
process2 = multiprocessing.Process(target=print_numbers)
# 启动进程
process1.start()
process2.start()
# 等待进程结束
process1.join()
process2.join()
print("Processes finished executing")
多进程创建机制:
进程间通信:
Queue
进行进程间数据传递示例:from multiprocessing import Process, Queue
def worker(q):
q.put("Hello from worker")
if __name__ == '__main__':
q = Queue()
p = Process(target=worker, args=(q,))
p.start()
print(q.get())
p.join()
Pipe
进行进程间数据传递示例:from multiprocessing import Process, Pipe
def worker(conn):
conn.send("Hello from worker")
conn.close()
if __name__ == '__main__':
parent_conn, child_conn = Pipe()
p = Process(target=worker, args=(child_conn,))
p.start()
print(parent_conn.recv())
p.join()
进程池:
进程池可以限制进程数量,避免进程过多导致的资源浪费。Pool
提供了多进程的并发执行。
from multiprocessing import Pool
import os
def task(n):
print(f"Process ID: {os.getpid()}, Task: {n}")
return n * n
if __name__ == '__main__':
with Pool(4) as pool:
results = pool.map(task, range(10))
print(results)
协程是一种轻量级的并发模型,允许在函数内部进行异步操作而不阻塞执行。协程适合处理大量的I/O密集型任务,如高并发的网络请求、爬虫等。协程通过async
和await
关键字实现。
使用asyncio
模块创建协程:
import asyncio
async def print_numbers():
for i in range(5):
print(i)
await asyncio.sleep(1)
async def main():
await asyncio.gather(print_numbers(), print_numbers())
# 运行事件循环
asyncio.run(main())
事件循环:
await
表达式上暂停当前协程,并切换到其他可执行的协程,直到所有协程完成。线程和进程的底层机制
threading
模块使用系统调用(如pthread_create
)来创建线程。GIL限制了同一时刻只有一个线程执行Python字节码,但在进行I/O操作时,GIL的影响较小。fork
)进行创建。Python的multiprocessing
模块使用系统调用(如fork
、spawn
)来创建进程,进程间通过IPC机制进行通信GIL(全局解释器锁)
multiprocessing
模块创建多个进程,每个进程都有自己的GIL。内存管理
malloc
和free
进行内存分配和释放。Python有一个内存池机制,以减少内存分配和释放的开销。