1. 同步
当线程在系统中运行时,线程的调度具有一定的透明性,通常程序无法准确控制线程的轮换执行,如果有需要,Python 可通过线程通信来保证线程协调运行。
同步:多个线程协按照一定的顺序协同完成某一任务。
为了实现同步,可以借助于 Event 对象来保持协调。
2. Event
Event是线程间通信间的机制之一:一个线程发送一个event信号,其他的线程则等待这个信号。常用在一个线程需要根据另外一个线程的状态来确定自己的下一步操作的情况。
Event原理:事件对象管理一个内部标志,通过set()方法将其设置为True,并使用clear()方法将其设置为False。wait()方法阻塞,直到标志为True。该标志初始为False。
Event类提供了如下几个方法:
-
is_set()
:当且仅当内部标志为True时返回True。 -
set()
:将内部标志设置为True。所有等待它成为True的线程都被唤醒。当标志保持在True的状态时,线程调用wait()是不会阻塞的。 -
clear()
:将内部标志重置为False。随后,调用wait()的线程将阻塞,直到另一个线程调用set()将内部标志重新设置为True。 -
wait(timeout=None)
:阻塞直到内部标志为真。如果内部标志在wait()方法调用时为True,则立即返回。否则,则阻塞,直到另一个线程调用set()将标志设置为True,或发生超时。该方法总是返回True,除非设置了timeout并发生超时。
3. 示例
# wait()默认timeout=None时,阻塞直到内部标志为真。
import threading
import time
def test0():
global event
event.clear()
print(f"{threading.currentThread().name}_start========")
time.sleep(1)
print(f"{threading.currentThread().name}_end========")
event.set()
def test1():
global event
event.wait()
print(f"{threading.currentThread().name}_end========")
event = threading.Event()
task0 = threading.Thread(target=test0, name="thread_test0")
task1 = threading.Thread(target=test1, name="thread_test1")
task0.start()
task1.start()
task0.join()
task1.join()
"""
运行结果:
thread_test0_start========
thread_test0_end========
thread_test1_end========
Process finished with exit code 0
"""
# wait()默认timeout=0.5时,被阻塞的线程直到超时继续向下运行。
import threading
import time
def test0():
global event
event.clear()
print(f"{threading.currentThread().name}_start========")
time.sleep(1)
print(f"{threading.currentThread().name}_end========")
event.set()
def test1():
global event
event.wait(timeout=0.5)
print(f"{threading.currentThread().name}_end========")
event = threading.Event()
task0 = threading.Thread(target=test0, name="thread_test0")
task1 = threading.Thread(target=test1, name="thread_test1")
task0.start()
task1.start()
task0.join()
task1.join()
"""
运行结果:
thread_test0_start========
thread_test1_end========
thread_test0_end========
Process finished with exit code 0
"""
注意:对于wait方法,可以理解为往下继续运行的条件有两个,一个是内部标志为True,另一个是Timeout时间限制,这两个条件中有一个满足,则被wait方法阻塞的线程就可以继续向下运行。