Python 简明教程
Python - Inter-Thread Communication
线程间通信是指在Python多线程程序内启用线程之间的通信和同步的过程。
Inter-Thread Communication refers to the process of enabling communication and synchronization between threads within a Python multi-threaded program.
通常,Python中的线程在一个进程内共享相同的内存空间,这允许它们通过 threading 模块提供的共享变量、对象和专门的同步机制来交换数据并协调其活动。
Generally, threads in Python share the same memory space within a process, which allows them to exchange data and coordinate their activities through shared variables, objects, and specialized synchronization mechanisms provided by the threading module.
为了促进线程间通信,threading模块提供了各种同步原语,如锁、事件、条件和信号量对象。在本教程中,您将学习如何使用事件和条件对象在多线程程序中提供线程之间的通信。
To facilitate inter-thread communication, the threading module provides various synchronization primitives like, Locks, Events, Conditions, and Semaphores objects. In this tutorial you will learn how to use the Event and Condition object for providing the communication between threads in a multi-threaded program.
The Event Object
事件对象管理内部标志的状态,以便线程可以等待或设置。 Event 对象提供了控制此标志状态的方法,允许线程根据共享条件同步它们的活动。
An Event object manages the state of an internal flag so that threads can wait or set. Event object provides methods to control the state of this flag, allowing threads to synchronize their activities based on shared conditions.
该标志最初为false并在set()方法下变为true,并通过clear()方法重置为false。wait()方法会阻塞,直到标志为true为止。
The flag is initially false and becomes true with the set() method and reset to false with the clear() method. The wait() method blocks until the flag is true.
以下是 Event 对象的关键方法-
Following are the key methods of the Event object −
-
is_set(): Return True if and only if the internal flag is true.
-
set(): Set the internal flag to true. All threads waiting for it to become true are awakened. Threads that call wait() once the flag is true will not block at all.
-
clear(): Reset the internal flag to false. Subsequently, threads calling wait() will block until set() is called to set the internal flag to true again.
-
wait(timeout=None): Block until the internal flag is true. If the internal flag is true on entry, return immediately. Otherwise, block until another thread calls set() to set the flag to true, or until the optional timeout occurs. When the timeout argument is present and not None, it should be a floating point number specifying a timeout for the operation in seconds.
Example
以下代码尝试模拟由 GREEN 或 RED 交通信号状态控制的交通流量。
The following code attempts to simulate the traffic flow being controlled by the state of traffic signal either GREEN or RED.
程序中有两个线程,分别针对两个不同的函数。 signal_state() 函数定期设置和重置事件,表示信号从绿色变为红色。
There are two threads in the program, targeting two different functions. The signal_state() function periodically sets and resets the event indicating change of signal from GREEN to RED.
traffic_flow() 函数等待事件被设置,并运行一个循环,直到它保持设置状态。
The traffic_flow() function waits for the event to be set, and runs a loop till it remains set.
from threading import Event, Thread
import time
terminate = False
def signal_state():
global terminate
while not terminate:
time.sleep(0.5)
print("Traffic Police Giving GREEN Signal")
event.set()
time.sleep(1)
print("Traffic Police Giving RED Signal")
event.clear()
def traffic_flow():
global terminate
num = 0
while num < 10 and not terminate:
print("Waiting for GREEN Signal")
event.wait()
print("GREEN Signal ... Traffic can move")
while event.is_set() and not terminate:
num += 1
print("Vehicle No:", num," Crossing the Signal")
time.sleep(1)
print("RED Signal ... Traffic has to wait")
event = Event()
t1 = Thread(target=signal_state)
t2 = Thread(target=traffic_flow)
t1.start()
t2.start()
# Terminate the threads after some time
time.sleep(5)
terminate = True
# join all threads to complete
t1.join()
t2.join()
print("Exiting Main Thread")
Output
执行上述代码时,您将获得以下输出 -
On executing the above code you will get the following output −
Waiting for GREEN Signal
Traffic Police Giving GREEN Signal
GREEN Signal ... Traffic can move
Vehicle No: 1 Crossing the Signal
Traffic Police Giving RED Signal
RED Signal ... Traffic has to wait
Waiting for GREEN Signal
Traffic Police Giving GREEN Signal
GREEN Signal ... Traffic can move
Vehicle No: 2 Crossing the Signal
Vehicle No: 3 Crossing the Signal
Traffic Police Giving RED Signal
Traffic Police Giving GREEN Signal
Vehicle No: 4 Crossing the Signal
Traffic Police Giving RED Signal
RED Signal ... Traffic has to wait
Traffic Police Giving GREEN Signal
Traffic Police Giving RED Signal
Exiting Main Thread
The Condition Object
Python 的 threading 模块中的 Condition 对象提供了更高级的同步机制。它允许线程在继续之前等待来自另一个线程的通知。Condition 对象始终与锁相关联,并提供用于线程之间信令的机制。
The Condition object in Python’s threading module provides a more advanced synchronization mechanism. It allows threads to wait for a notification from another thread before proceeding. The Condition object are always associated with a lock and provide mechanisms for signaling between threads.
以下是 threading.Condition() 类的语法 -
Following is the syntax of the threading.Condition() class −
threading.Condition(lock=None)
以下是 Condition 对象的关键方法 -
Below are the key methods of the Condition object −
-
acquire(*args): Acquire the underlying lock. This method calls the corresponding method on the underlying lock; the return value is whatever that method returns.
-
release(): Release the underlying lock. This method calls the corresponding method on the underlying lock; there is no return value.
-
wait(timeout=None): This method releases the underlying lock, and then blocks until it is awakened by a notify() or notify_all() call for the same condition variable in another thread, or until the optional timeout occurs. Once awakened or timed out, it re-acquires the lock and returns.
-
wait_for(predicate, timeout=None): This utility method may call wait() repeatedly until the predicate is satisfied, or until a timeout occurs. The return value is the last return value of the predicate and will evaluate to False if the method timed out.
-
notify(n=1): This method wakes up at most n of the threads waiting for the condition variable; it is a no-op if no threads are waiting.
-
notify_all(): Wake up all threads waiting on this condition. This method acts like notify(), but wakes up all waiting threads instead of one. If the calling thread has not acquired the lock when this method is called, a RuntimeError is raised.
Example
此示例演示了使用 Python 的 threading 模块的 Condition 对象进行线程间通信的简单形式。此处, thread_a 和 thread_b 使用 Condition 对象进行通信, thread_a 等待,直到它从 thread_b 接收通知。 thread_b 在通知 thread_a 之前休眠 2 秒,然后完成。
This example demonstrates a simple form of inter-thread communication using the Condition object of the Python’s threading module. Here thread_a and thread_b are communicated using a Condition object, the thread_a waits until it receives a notification from thread_b. the thread_b sleeps for 2 seconds before notifying thread_a and then finishes.
from threading import Condition, Thread
import time
c = Condition()
def thread_a():
print("Thread A started")
with c:
print("Thread A waiting for permission...")
c.wait()
print("Thread A got permission!")
print("Thread A finished")
def thread_b():
print("Thread B started")
with c:
time.sleep(2)
print("Notifying Thread A...")
c.notify()
print("Thread B finished")
Thread(target=thread_a).start()
Thread(target=thread_b).start()
Output
执行上述代码时,您将获得以下输出 -
On executing the above code you will get the following output −
Thread A started
Thread A waiting for permission...
Thread B started
Notifying Thread A...
Thread B finished
Thread A got permission!
Thread A finished
Example
以下代码演示了如何使用 Condition 对象在线程之间提供通信。其中,线程 t2 运行 taskB() 函数,线程 t1 运行 taskA() 函数。t1 线程获取条件并通知它。
Here is another code demonstrating how the Condition object is used for providing the communication between threads. In this, the thread t2 runs the taskB() function, and the thread t1 runs the taskA() function. The t1 thread acquires the condition and notifies it.
到那时,t2 线程处于等待状态。释放条件后,等待线程会继续使用通知函数产生的随机数。
By that time, the t2 thread is in a waiting state. After the condition is released, the waiting thread proceeds to consume the random number generated by the notifying function.
from threading import Condition, Thread
import time
import random
numbers = []
def taskA(c):
for _ in range(5):
with c:
num = random.randint(1, 10)
print("Generated random number:", num)
numbers.append(num)
print("Notification issued")
c.notify()
time.sleep(0.3)
def taskB(c):
for i in range(5):
with c:
print("waiting for update")
while not numbers:
c.wait()
print("Obtained random number", numbers.pop())
time.sleep(0.3)
c = Condition()
t1 = Thread(target=taskB, args=(c,))
t2 = Thread(target=taskA, args=(c,))
t1.start()
t2.start()
t1.join()
t2.join()
print("Done")
执行此代码时,它将生成以下 output -
When you execute this code, it will produce the following output −
waiting for update
Generated random number: 2
Notification issued
Obtained random number 2
Generated random number: 5
Notification issued
waiting for update
Obtained random number 5
Generated random number: 1
Notification issued
waiting for update
Obtained random number 1
Generated random number: 9
Notification issued
waiting for update
Obtained random number 9
Generated random number: 2
Notification issued
waiting for update
Obtained random number 2
Done