Python - 线程间通信
大家好,未来的 Python 大师们!今天,我们将开始一段激动人心的旅程,深入了解 Python 中的线程间通信。如果你是编程新手,也不用担心——我会作为你的友好向导,一步一步地解释。那么,让我们开始吧!
什么是线程间通信?
在我们深入研究细节之前,先来了解一下线程间通信是什么。想象一下,你在一个团队中工作,负责一个大型项目。你们都在处理不同的部分,但有时你需要分享信息或者协调工作。程序中的线程也是如此,线程间通信就是它们彼此“交谈”的方式。
事件对象
让我们从线程通信的最简单方式开始:事件对象。
什么是事件对象?
事件对象就像一个可以设置或清除的标志。线程可以等待这个标志被设置后再继续执行。这有点像在过马路之前等待绿灯。
如何使用事件对象
来看一个简单的例子:
import threading
import time
def waiter(event):
print("服务员:我在等待事件被设置...")
event.wait()
print("服务员:事件被设置了!我现在可以继续了。")
def setter(event):
print("设置者:我将在3秒后设置事件...")
time.sleep(3)
event.set()
print("设置者:我已经设置了事件!")
# 创建一个事件对象
e = threading.Event()
# 创建并启动线程
t1 = threading.Thread(target=waiter, args=(e,))
t2 = threading.Thread(target=setter, args=(e,))
t1.start()
t2.start()
# 等待两个线程完成
t1.join()
t2.join()
print("主线程:全部完成!")
让我们分解一下:
- 我们导入了
threading
模块来创建线程,导入了time
模块来添加延迟。 - 我们定义了两个函数:
waiter
和setter
。 -
waiter
函数使用event.wait()
等待事件被设置。 -
setter
函数等待3秒钟(模拟一些工作)然后使用event.set()
设置事件。 - 我们创建了一个事件对象
e
。 - 我们创建了两个线程,每个函数一个,并将事件对象传递给两个线程。
- 我们启动了两个线程,然后使用
join()
等待它们完成。
运行这个程序后,你会看到服务员在等待,然后3秒后,设置者设置了事件,服务员继续执行。
条件对象
现在,让我们提高一个层次,看看条件对象。它就像是事件对象的更复杂的表亲。
什么是条件对象?
条件对象允许线程等待某些条件变为真。这就像在聚会开始游戏之前等待特定的客人到达。
如何使用条件对象
下面是使用条件对象的一个例子:
import threading
import time
import random
# 共享资源
items = []
condition = threading.Condition()
def producer():
global items
for i in range(5):
time.sleep(random.random()) # 模拟不同的生产时间
with condition:
items.append(f"项目 {i}")
print(f"生产者添加了项目 {i}")
condition.notify() # 通知消费者项目可用
def consumer():
global items
while True:
with condition:
while not items:
print("消费者正在等待...")
condition.wait()
item = items.pop(0)
print(f"消费者移除了 {item}")
time.sleep(random.random()) # 模拟不同的消费时间
# 创建并启动线程
producer_thread = threading.Thread(target=producer)
consumer_thread = threading.Thread(target=consumer)
producer_thread.start()
consumer_thread.start()
# 等待生产者完成
producer_thread.join()
# 停止消费者(它在无限循环中)
consumer_thread.daemon = True
让我们分解一下:
- 我们创建了一个共享资源
items
和一个条件对象。 -
producer
函数向列表中添加项目并通知消费者。 -
consumer
函数等待项目可用,然后移除并“消费”它们。 - 我们使用
with condition:
来自动获取和释放条件的锁。 -
condition.wait()
释放锁并等待通知。 -
condition.notify()
唤醒一个等待的线程。
这个例子演示了一个经典的生产者-消费者场景,一个线程生产项目,另一个线程消费它们。
事件对象和条件对象比较
以下是事件对象和条件对象的快速比较:
特性 | 事件 | 条件 |
---|---|---|
目的 | 简单信号 | 复杂同步 |
状态 | 二进制(设置/清除) | 可以有多个状态 |
等待 | 线程等待事件被设置 | 线程等待特定条件 |
通知 | 所有等待的线程都被通知 | 可以通知一个或所有等待的线程 |
用例 | 简单的“行/不行”场景 | 生产者-消费者问题,复杂同步 |
结论
恭喜你!你已经迈出了在 Python 中进行线程间通信的第一步。我们介绍了事件对象进行简单信号,以及条件对象进行更复杂的同步场景。
记住,就像学习任何新语言一样,实践是完美的。尝试使用这些对象编写你自己的程序。也许可以创建一个简单的聊天系统,其中线程代表不同的用户,或者使用事件模拟交通灯系统。
线程间通信一开始可能看起来很复杂,但时间和实践后,你将能够像指挥家指挥乐团一样协调线程。继续编码,继续学习,最重要的是,玩得开心!
Credits: Image by storyset