概念
多进程是指一个程序同时运行多个进程。每个进程都有自己的内存空间和资源,进程之间通过进程间通信(IPC)来共享数据。
优点
独立性:每个进程都有独立的内存空间,一个进程的崩溃不会影响其他进程。
并行性:可以利用多核 CPU 的优势,实现真正的并行计算。
缺点
资源消耗:每个进程都有自己的内存空间,因此资源消耗较大。
通信成本:进程间通信需要通过 IPC,通信成本较高。
概念
多线程是指一个进程内部同时运行多个线程。线程共享进程的内存空间,因此线程间的通信成本较低。
优点
轻量级:线程比进程轻量,创建和销毁的开销较小。
通信方便:线程共享进程的内存空间,通信成本较低。
缺点
GIL 限制:Python 的全局解释器锁(GIL)限制了同一时刻只有一个线程可以执行 Python 字节码,因此多线程在 CPU 密集型任务中无法实现真正的并行计算。Python中的多线程并不是真并行,而是“交替执行” 。由于 GIL 的存在,执行计算密集任务可能会导致多个线程争抢1个GIL,让任务比普通的更慢。
线程安全:线程共享内存空间,因此需要处理线程安全问题,如锁、信号量等。
概念
协程是一种基于事件驱动的并发编程模型。协程通过 async
和 await
关键字实现,可以在 I/O 操作时挂起和恢复,从而实现高效的并发。
优点
高效:协程是基于事件驱动的,适合处理 I/O 密集型任务,如网络请求、文件读写等。
轻量级:协程比线程更轻量,创建和切换的开销较小。
缺点
适用场景有限:协程主要用于 I/O 密集型任务,对于 CPU 密集型任务效果不明显。
复杂性:协程的代码逻辑可能较为复杂,需要理解 async
和 await
的使用。
multiprocessing
模块实现多进程import time
import multiprocessing
# 定义任务函数
def worker(task_id, result_queue):
print(f"Task {task_id} is starting.")
time.sleep(1) # 模拟耗时操作
result = f"Result from Task {task_id}"
result_queue.put(result) # 将结果放入队列
print(f"Task {task_id} is finished.")
# 主程序
def main():
num_tasks = 5 # 定义任务数量
result_queue = multiprocessing.Queue() # 创建一个队列用于收集结果
processes = []
for i in range(num_tasks):
process = multiprocessing.Process(target=worker, args=(i, result_queue))
processes.append(process)
process.start()
for process in processes:
process.join() # 等待所有进程完成
# 收集结果
results = []
while not result_queue.empty():
results.append(result_queue.get())
print("All processes have finished.")
print("Results:", results)
if __name__ == "__main__":
main()
multiprocessing
和 multiprocessing.dummy
分别实现多进程和多线程。import time
import multiprocessing
import multiprocessing.dummy
# 定义任务函数
def task_function(task_id):
print(f"Task {task_id} is starting.")
time.sleep(1) # 模拟耗时操作
print(f"Task {task_id} is finished.")
# 使用 multiprocessing 实现多进程
def run_multiprocessing(num_tasks):
processes = []
for i in range(num_tasks):
process = multiprocessing.Process(target=task_function, args=(i,))
processes.append(process)
process.start()
for process in processes:
process.join()
# 使用 multiprocessing.dummy 实现多线程
def run_multithreading(num_tasks):
pool = multiprocessing.dummy.Pool(processes=num_tasks)
pool.map(task_function, range(num_tasks))
pool.close()
pool.join()
# 主程序
def main():
num_tasks = 5 # 定义任务数量
print("Running multiprocessing...")
run_multiprocessing(num_tasks)
print("\nRunning multithreading...")
run_multithreading(num_tasks)
if __name__ == "__main__":
main()
multiprocessing
和 threading
模块实现多进程和多线程结合使用import time
import threading
import multiprocessing
# 定义任务函数
def task_function(thread_id, process_id):
print(f"Thread {thread_id} in Process {process_id} is starting.")
time.sleep(1) # 模拟耗时操作
print(f"Thread {thread_id} in Process {process_id} is finished.")
# 定义多线程函数
def process_function(process_id, num_threads):
threads = []
for i in range(num_threads):
thread = threading.Thread(target=task_function, args=(i, process_id))
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
# 主程序
def main():
num_processes = 3 # 定义进程数量
num_threads_per_process = 2 # 定义每个进程中的线程数量
processes = []
for i in range(num_processes):
process = multiprocessing.Process(target=process_function, args=(i, num_threads_per_process))
processes.append(process)
process.start()
for process in processes:
process.join()
print("All processes and threads have finished.")
if __name__ == "__main__":
main()
python 的 multiprocessing模块提供了多种进程间通信的方法,包括队列、管道、共享内存、管理器和锁等。这些方法可以根据具体需求选择使用,以实现复杂的并发任务。
队列(Queue):适用于简单的消息传递。
管道(Pipe):适用于两个进程之间的双向通信。
共享内存(Shared Memory):适用于共享简单的数据类型。
管理器(Manager):适用于共享复杂的数据结构。
锁(Lock):用于同步访问共享资源。
1. 队列(Queue)
multiprocessing.Queue
是一个线程和进程安全的队列实现,用于在进程之间传递消息。
import multiprocessing
import time
def worker(task_id, queue):
print(f"Task {task_id} is starting.")
time.sleep(1) # 模拟耗时操作
result = f"Result from Task {task_id}"
queue.put(result) # 将结果放入队列
print(f"Task {task_id} is finished.")
def main():
num_tasks = 5
result_queue = multiprocessing.Queue() # 创建一个队列
processes = []
for i in range(num_tasks):
process = multiprocessing.Process(target=worker, args=(i, result_queue))
processes.append(process)
process.start()
for process in processes:
process.join() # 等待所有进程完成
# 收集结果
results = []
while not result_queue.empty():
results.append(result_queue.get())
print("All processes have finished.")
print("Results:", results)
if __name__ == "__main__":
main()
2. 管道(Pipe)
multiprocessing.Pipe
提供了一个双向通信通道,可以用于两个进程之间的通信。
import multiprocessing
import time
def worker(conn):
print("Worker is starting.")
time.sleep(1) # 模拟耗时操作
conn.send("Hello from worker!") # 发送消息
conn.close()
print("Worker is finished.")
def main():
parent_conn, child_conn = multiprocessing.Pipe() # 创建管道
process = multiprocessing.Process(target=worker, args=(child_conn,))
process.start()
print("Main process is waiting for message.")
message = parent_conn.recv() # 接收消息
print("Received message:", message)
process.join()
print("Main process is finished.")
if __name__ == "__main__":
main()
3. 共享内存(Shared Memory)
multiprocessing
提供了 Value
和 Array
,用于在进程之间共享数据。
import multiprocessing
import time
def worker(shared_value, shared_array):
print("Worker is starting.")
shared_value.value = 42 # 修改共享值
for i in range(len(shared_array)):
shared_array[i] = i * i # 修改共享数组
time.sleep(1)
print("Worker is finished.")
def main():
shared_value = multiprocessing.Value('i', 0) # 创建共享值
shared_array = multiprocessing.Array('i', 5) # 创建共享数组
process = multiprocessing.Process(target=worker, args=(shared_value, shared_array))
process.start()
process.join()
print("Shared value:", shared_value.value)
print("Shared array:", list(shared_array))
if __name__ == "__main__":
main()
4. 管理器(Manager)
multiprocessing.Manager
提供了一种高级的共享数据机制,可以创建一个管理器对象,用于在多个进程之间共享复杂的数据结构。
import multiprocessing
import time
def worker(dictionary, list_):
dictionary[1] = '1'
dictionary['2'] = 2
dictionary[0.25] = None
list_.reverse()
def main():
with multiprocessing.Manager() as manager:
shared_dict = manager.dict() # 创建共享字典
shared_list = manager.list(range(10)) # 创建共享列表
process = multiprocessing.Process(target=worker, args=(shared_dict, shared_list))
process.start()
process.join()
print("Shared dictionary:", shared_dict)
print("Shared list:", shared_list)
if __name__ == "__main__":
main()
5. 锁(Lock)
multiprocessing.Lock
提供了一种同步机制,用于在多个进程之间同步访问共享资源。
import multiprocessing
import time
def worker(lock, counter):
with lock: # 使用上下文管理器获取锁
print(f"Worker {counter} is starting.")
time.sleep(1)
print(f"Worker {counter} is finished.")
def main():
lock = multiprocessing.Lock() # 创建锁
processes = []
for i in range(5):
process = multiprocessing.Process(target=worker, args=(lock, i))
processes.append(process)
process.start()
for process in processes:
process.join()
print("All processes have finished.")
if __name__ == "__main__":
main()
共享变量:直接使用全局变量进行通信。
锁(Lock):使用 threading.Lock
确保线程安全。
条件变量(Condition):使用 threading.Condition
实现线程间的同步和通知。
队列(Queue):使用 queue.Queue
实现线程间的消息传递。
事件(Event):使用 threading.Event
实现线程间的同步信号。
1. 共享变量
在 multiprocessing.dummy
中,线程共享内存空间,因此可以直接使用共享变量进行通信。
from multiprocessing.dummy import Pool as ThreadPool
import time
# 共享变量
shared_data = []
def worker(task_id):
global shared_data
shared_data.append(f"Result from Task {task_id}")
time.sleep(1) # 模拟耗时操作
print(f"Task {task_id} finished.")
def main():
pool = ThreadPool(3) # 创建线程池
pool.map(worker, range(5)) # 执行任务
pool.close()
pool.join()
print("All tasks finished.")
print("Shared data:", shared_data)
if __name__ == "__main__":
main()
2. 锁(Lock)
虽然 multiprocessing.dummy
没有直接提供锁,但可以使用 threading.Lock
来同步线程。
from multiprocessing.dummy import Pool as ThreadPool
import threading
import time
# 共享变量和锁
shared_data = []
lock = threading.Lock()
def worker(task_id):
with lock: # 使用锁确保线程安全
shared_data.append(f"Result from Task {task_id}")
print(f"Task {task_id} finished.")
def main():
pool = ThreadPool(3) # 创建线程池
pool.map(worker, range(5)) # 执行任务
pool.close()
pool.join()
print("All tasks finished.")
print("Shared data:", shared_data)
if __name__ == "__main__":
main()
3. 条件变量(Condition)
multiprocessing.dummy
没有直接提供条件变量,但可以使用 threading.Condition
。
import threading
from multiprocessing.dummy import Pool as ThreadPool
import time
condition = threading.Condition()
shared_resource = 0
def producer():
global shared_resource
with condition:
shared_resource += 1
print(f"Produced {shared_resource}")
condition.notify() # 通知等待的线程
def consumer():
global shared_resource
with condition:
condition.wait() # 等待资源可用
print(f"Consumed {shared_resource}")
def main():
producer_thread = threading.Thread(target=producer)
consumer_thread = threading.Thread(target=consumer)
producer_thread.start()
consumer_thread.start()
producer_thread.join()
consumer_thread.join()
print("All tasks finished.")
if __name__ == "__main__":
main()
4. 队列(Queue)
multiprocessing.dummy
没有直接提供队列,但可以使用 queue.Queue
。
import queue
from multiprocessing.dummy import Pool as ThreadPool
import time
q = queue.Queue()
def producer():
for i in range(5):
time.sleep(1)
q.put(i)
print(f"Produced {i}")
def consumer():
while True:
item = q.get()
print(f"Consumed {item}")
q.task_done()
def main():
producer_thread = threading.Thread(target=producer)
consumer_thread = threading.Thread(target=consumer)
producer_thread.start()
consumer_thread.start()
producer_thread.join()
q.join() # 等待队列为空
print("All tasks finished.")
if __name__ == "__main__":
main()
5. 事件(Event)
multiprocessing.dummy
没有直接提供事件,但可以使用 threading.Event
。
import threading
from multiprocessing.dummy import Pool as ThreadPool
import time
event = threading.Event()
def worker():
print("Worker: Waiting for event...")
event.wait() # 等待事件被设置
print("Worker: Event received.")
def main():
worker_thread = threading.Thread(target=worker)
worker_thread.start()
time.sleep(2) # 模拟耗时操作
event.set() # 设置事件
worker_thread.join()
print("All tasks finished.")
if __name__ == "__main__":
main()
Python 中多线程通信的几种常见方法,
共享变量:通过锁(Lock
)确保线程安全。
锁(Lock):用于同步线程对共享资源的访问。
条件变量(Condition):用于线程间的同步和通知。
队列(Queue):线程安全的队列,用于线程间的消息传递。
事件(Event):用于线程间的同步信号。
1. 共享变量
import threading
# 共享变量
shared_counter = 0
lock = threading.Lock()
def increment():
global shared_counter
with lock: # 确保线程安全
shared_counter += 1
print(f"Counter incremented to {shared_counter}")
def main():
threads = []
for _ in range(5):
thread = threading.Thread(target=increment)
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
print(f"Final counter value: {shared_counter}")
if __name__ == "__main__":
main()
# 共享变量的用途:
# 共享变量 shared_counter 用于简单的计数。
# 每个线程将计数器加 1,并打印当前值。
# 目的是展示如何通过锁确保线程安全地更新共享变量。
# 锁的使用:
# 使用 lock 确保 shared_counter 的更新是线程安全的。
# 锁的范围是 shared_counter += 1 操作,确保每次只有一个线程可以修改计数器。
2. 锁(Lock)
import threading
lock = threading.Lock()
shared_resource = 0
def worker():
global shared_resource
with lock: # 使用上下文管理器获取锁
temp = shared_resource
temp += 1
time.sleep(0.1) # 模拟耗时操作
shared_resource = temp
print(f"Resource updated to {shared_resource}")
def main():
threads = []
for _ in range(5):
thread = threading.Thread(target=worker)
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
print(f"Final shared resource value: {shared_resource}")
if __name__ == "__main__":
main()
# 共享变量的用途
# 共享变量 shared_resource 用于模拟资源更新。
# 每个线程读取当前值,将其加 1,然后写回共享变量。
# 目的是展示如何在有耗时操作(如 time.sleep(0.1))的情况下,通过锁确保线程安全地更新共享资源。
# 锁的使用
# 使用 lock 确保 shared_resource 的更新是线程安全的。
# 锁的范围包括读取、修改和写回共享资源的整个过程,确保在有耗时操作时,其他线程不会干扰当前线程的操作。
3. 条件变量(Condition)
import threading
import time
condition = threading.Condition()
item_produced = False
def producer():
global item_produced
with condition:
print("Producer: Producing item...")
item_produced = True
condition.notify() # 通知等待的线程
print("Producer: Item produced and notified.")
def consumer():
global item_produced
with condition:
print("Consumer: Waiting for item...")
condition.wait_for(lambda: item_produced) # 等待条件满足
print("Consumer: Item consumed.")
item_produced = False
def main():
producer_thread = threading.Thread(target=producer)
consumer_thread = threading.Thread(target=consumer)
producer_thread.start()
consumer_thread.start()
producer_thread.join()
consumer_thread.join()
if __name__ == "__main__":
main()
4. 队列(Queue)
import threading
import queue
import time
def producer(q):
for i in range(5):
print(f"Producer: Producing item {i}")
q.put(i)
time.sleep(0.5)
def consumer(q):
while True:
item = q.get()
print(f"Consumer: Consumed item {item}")
q.task_done()
def main():
q = queue.Queue()
producer_thread = threading.Thread(target=producer, args=(q,))
consumer_thread = threading.Thread(target=consumer, args=(q,))
producer_thread.start()
consumer_thread.start()
producer_thread.join()
q.join() # 等待队列为空
consumer_thread.join()
if __name__ == "__main__":
main()
5. 事件(Event)
import threading
import time
event = threading.Event()
def waiter():
print("Waiter: Waiting for event...")
event.wait() # 等待事件被设置
print("Waiter: Event received.")
def setter():
time.sleep(2) # 模拟耗时操作
print("Setter: Setting event.")
event.set() # 设置事件
def main():
waiter_thread = threading.Thread(target=waiter)
setter_thread = threading.Thread(target=setter)
waiter_thread.start()
setter_thread.start()
waiter_thread.join()
setter_thread.join()
if __name__ == "__main__":
main()
import asyncio
# 使用 async def 定义协程函数
async def fetch_data(task_id):
print(f"Fetching data for task {task_id}...")
await asyncio.sleep(2) # 模拟异步 I/O 操作
print(f"Data fetched for task {task_id}.")
return f"Sample data for task {task_id}"
# 使用 asyncio.run() 运行协程
async def main():
data = await fetch_data(1)
print("Received data:", data)
# 使用 asyncio.gather() 并发运行多个协程
async def main2():
tasks = [fetch_data(i) for i in range(3)]
results = await asyncio.gather(*tasks)
print("Received data:", results)
if __name__ == "__main__":
asyncio.run(main())
asyncio.run(main2())
网络请求
协程非常适合处理网络请求,如使用 aiohttp
库进行异步 HTTP 请求。
import asyncio
import aiohttp
async def fetch_url(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
data = await response.text()
print(f"Fetched {url}: {data[:100]}...")
async def main():
urls = [
"http://example.com",
"http://example.org",
"http://example.net"
]
tasks = [fetch_url(url) for url in urls]
await asyncio.gather(*tasks)
if __name__ == "__main__":
asyncio.run(main())
文件读写
协程也可以用于文件读写操作,如使用 aiofiles
库进行异步文件操作。
import asyncio
import aiofiles
async def read_file(file_path):
async with aiofiles.open(file_path, 'r') as file:
content = await file.read()
print(f"Read from {file_path}: {content[:100]}...")
async def main():
files = ["file1.txt", "file2.txt", "file3.txt"]
tasks = [read_file(file) for file in files]
await asyncio.gather(*tasks)
if __name__ == "__main__":
asyncio.run(main())
错误处理
协程中的错误可以通过 try-except
块捕获。
import asyncio
async def fetch_data(task_id):
try:
print(f"Task {task_id}: Fetching data...")
await asyncio.sleep(2)
print(f"Task {task_id}: Data fetched.")
return f"Sample data {task_id}"
except Exception as e:
print(f"Task {task_id}: Error occurred: {e}")
async def main():
tasks = [fetch_data(i) for i in range(3)]
results = await asyncio.gather(*tasks, return_exceptions=True)
print("Received data:", results)
if __name__ == "__main__":
asyncio.run(main())
超时处理
协程支持超时处理,可以使用 asyncio.wait_for()
import asyncio
async def fetch_data():
print("Fetching data...")
await asyncio.sleep(5) # 模拟耗时操作
print("Data fetched.")
return "Sample data"
async def main():
try:
data = await asyncio.wait_for(fetch_data(), timeout=3)
print("Received data:", data)
except asyncio.TimeoutError:
print("Timeout occurred.")
if __name__ == "__main__":
asyncio.run(main())
仅适用于 I/O 密集型任务
协程主要适用于 I/O 密集型任务,对于 CPU 密集型任务效果不明显。
事件循环的限制
协程运行在单个线程中,依赖于事件循环。如果事件循环被阻塞,协程将无法运行。
asyncio.Queue
:适用于生产者和消费者模式,支持异步操作。
asyncio.Event
:用于简单的同步场景,一个协程可以设置事件,另一个协程可以等待事件。
asyncio.Condition
:提供更复杂的同步机制,适用于需要条件变量的场景。
asyncio.create_task
:用于并发运行多个协程,协程间可以通过共享变量或其他机制进行通信
1. 使用 asyncio.Queue
实现协程间通信
asyncio.Queue
是一个异步队列,支持 async/await
语法,适用于协程间的通信。
import asyncio
async def producer(queue):
for i in range(5):
print(f"Producing item {i}")
await queue.put(i) # 将数据放入队列
await asyncio.sleep(1)
async def consumer(queue):
while True:
item = await queue.get() # 从队列中获取数据
print(f"Consuming item {item}")
queue.task_done() # 标记任务完成
async def main():
queue = asyncio.Queue() # 创建异步队列
producer_task = asyncio.create_task(producer(queue)) # 创建生产者任务
consumer_task = asyncio.create_task(consumer(queue)) # 创建消费者任务
await producer_task # 等待生产者任务完成
await queue.join() # 等待队列中的所有任务完成
consumer_task.cancel() # 取消消费者任务
asyncio.run(main())
2. 使用 asyncio.Event
实现协程间通信
asyncio.Event
可用于协程间的同步,一个协程可以设置事件,另一个协程可以等待事件。
import asyncio
async def waiter(event):
print("Waiter: Waiting for event...")
await event.wait() # 等待事件
print("Waiter: Event received.")
async def setter(event):
print("Setter: Setting event...")
await asyncio.sleep(2) # 模拟耗时操作
event.set() # 设置事件
async def main():
event = asyncio.Event()
waiter_task = asyncio.create_task(waiter(event))
setter_task = asyncio.create_task(setter(event))
await waiter_task # 等待等待者任务完成
await setter_task # 等待设置者任务完成
asyncio.run(main())
3. 使用 asyncio.Condition
实现协程间通信
asyncio.Condition
提供了更复杂的同步机制,允许协程在满足特定条件时进行通信。
import asyncio
async def producer(condition, shared_list):
async with condition:
shared_list.append("Item")
print("Producer: Item produced.")
condition.notify() # 通知等待的协程
async def consumer(condition, shared_list):
async with condition:
await condition.wait() # 等待条件变量
item = shared_list.pop()
print(f"Consumer: Item consumed: {item}")
async def main():
shared_list = []
condition = asyncio.Condition()
producer_task = asyncio.create_task(producer(condition, shared_list))
consumer_task = asyncio.create_task(consumer(condition, shared_list))
await producer_task
await consumer_task
asyncio.run(main())
4. 使用 asyncio.create_task
实现协程间通信
asyncio.create_task
可用于并发运行多个协程,这些协程可以通过共享变量或其他机制进行通信。
import asyncio
async def task1(shared_data):
await asyncio.sleep(1)
shared_data.append("Task 1 result")
print("Task 1 completed.")
async def task2(shared_data):
await asyncio.sleep(2)
shared_data.append("Task 2 result")
print("Task 2 completed.")
async def main():
shared_data = []
task1_coro = asyncio.create_task(task1(shared_data)) # 创建任务1
task2_coro = asyncio.create_task(task2(shared_data)) # 创建任务2
await task1_coro # 等待任务1完成
await task2_coro # 等待任务2完成
print("Shared data:", shared_data)
asyncio.run(main())