- 线程 V.S 进程
- 线程本地数据
- 概念
- 线程对象
- 概念
- 方法
- 锁对象:Lock
- 概念
- 方法
- 应用场景
- 示例
- 1.
- 未使用Lock时
- 使用Lock时
- 2.
- 使用Lock且只请求一次
- 使用Lock且请求同一Lock多次
- 递归锁对象:RLock
- 概念
- 方法
- Lock V.S RLock
- 示例
- 1.
- 未使用RLock时
- 使用RLock时
- 2.
- 未使用RLock时
- 使用RLock时
- 条件对象:Condition
- 概念
- 方法
- 应用场景
- 示例
- 1.
- 信号量对象:Semaphore
- 概念
- 应用场景
- 示例
- 1.
- 2.
- 3.
- Without Semaphore
- With Semaphore
- 事件对象:Event
- 概念
- 方法
- 示例
- 函数传递
- 1.
- 2.
- 实例化
- 1.
- 定时器对象:Timer
- 栅栏对象:Barrier
- 在with语句中使用锁、条件和信号量
- 参考文章
此文主要功用是总结threading相关的概念、类、方法和示例代码
线程 V.S 进程 线程本地数据 概念
// 线程本地数据是特定线程的数据 // 管理线程本地数据只需要创建一个local(或者一个子类型)的实例并在实例中存储属性 import threading data = threading.local() # 线程本地数据threading.local的实例data data.x = 1 # 实例data的x属性的值是1 data.address = 500 # 实例data的x属性的值是1 print(data.x) print(data.address) -------------------------------------------------------------------- C:python34python.exe C:/Users/E910600/PycharmProjects/0705/test2.py 1 500 Process finished with exit code 0线程对象 概念
\ 创建线程对象 (threading.thread)
threading.Thread(group=None, target=None, name=None, args=(), kwargs=(), *, daemon=None)
group:默认为None,为日后ThreadGroup类实现而保留
target:默认为None,是用于run()方法调用的可调用对象
name:默认为'Thread-N'格式构成的一个唯一的名称,其中N是小的十进制数;
args:默认为(),是用于调用目标函数的参数元组
kwargs:默认为(),是调用目标函数的关键字参数字典
daemon:默认为None,即线程将继承当前线程的说胡模式属性(主线程不是守护线程)
即主线程创建的所有线程默认为daemon=None;
如赋值daemon非None的值,则显示地设置该线程是否为守护模式, 即当剩下的线程均为守护线程时整个Python程序会退出,但可能守护线程的资源(如已打开的文档,数据库事务等)可能未被正确释放。如果想线程正常停止,应设为非守护线程并使用合适的信号机制,比如Event。
应当在start()前设好,不然会抛出RuntimeError
如果子类型重载了构造函数,则一定要确保在做任何事情前先发起基类构造器(Thread.__init__())
方法
| 方法 | 作用 |
|---|---|
| threading.Thread.start() | 表示开始线程活动。 在一个线程中最多被调用一次,它安排对象的run()方法在一个独立的控制进程中调用。如果被调用超过一次,会抛出RuntimeError |
| threading.Thread.run() | 表示线程活动的方法。 可在子类型中重载这个方法,标准的run()方法会对target参数传递给该对象构造器的可调用对象发起调用,并附带从args和kwargs参数分别获取的位置和关键字参数 |
| threading.Thread.join(timeout=None) | 阻塞调用该方法的线程直到线程终止,e.g.正常终结,抛出未处理异常或直到发出超时。 timeout为默认None或不存在时,会阻塞直到线程终结; 不为默认None,参数存在时,它应是一个用于指定操作超时的以秒为单位的浮点数(或者分数)。 因为join()总是返回None,所以一定要在join()后调用is_alive()才能判断是否发生超时,即如线程仍然存活则join超时且一个线程可被join()多次 如尝试加入当前进程会引起死锁,或join()一个尚未开始的线程,join()会引起RuntimeError异常 |
| threading.Thread.is_alive() | 返回线程是否存活。 当run方法开始到run方法结束,is_alive() |
| threading.active_count() | 返回当前存活的thread对象的数量,应该同enumerate()返回的列表长度一致,或者说threading.current_count() = len(enumerate()) |
| threading.current_thread() | 返回当前对应调用者的控制线程的Thread对象() 如果调用者的控制线程不是利用threading创建,会返回一个功能受限的虚拟线程对象。 主线程对象对应Python程序里面初始的控制线程,其不是一个守护线程。 虚拟线程对象可被创建,其对应于“外部线程“的线程对象,它们是在线程模块外部启动的控制线程,比如直接来自C代码。虚拟线程对象功能受限,总被认为是存活和守护模式,不能被join()。因为无法检测外来线程的终结,它们永远不会被删除。 |
| threading.Thread.getName() | 线程名字可传递给构造函数,也可通过name属性读取或修改 |
| threading.get_ident() | 返回当前线程的 “线程标识符”,为非零的整数,作为含有线程相关数据的字典的索引 线程标识符可能会在线程退出,新线程创建时被复用 |
| threading.enumerate() | 以列表形式返回当前存活的Thread对象,该列表包含守护线程,current_thread() 创建的虚拟线程对象和主线程 |
| threading.main_thread() | 返回主thread对象,一般情况下主线程是python解释器开始时创建的线程 |
| threading.settrace(func) | 为所有threading模块开始的线程设置追踪函数 在每个线程的run()方法被调用前,func会被传递给sys.settrace() |
| threading.setprofile(func) | 为所有threading模块开始的线程设置性能测试函数 在每个线程的run()方法被调用前,func会被传递给sys.setprofile() |
| threading.stack_size([size]) | 返回创建线程时用的堆栈大小 可选参数size指定之后新建的线程的堆栈大小,而且一定要是0或最小是32768的一个正整数 如size没有指定,默认是0 如不支持改变线程堆栈大小,会抛出runtimeerror错误 如支持但制定的堆栈大小不合法,会抛出valueerror错误并且不会修改堆栈大小 |
| threading.TIMEOUT_MAX | 阻塞函数中形参timeout允许的最大值,传入超过这个值的timeout会抛出overflowerror异常 |
该模块的设计基于java的线程模型
在java里lock和条件变量是每个对象的基础特性,但在python里面它们被独立成了单独的对象
目前还没有优先级,没有线程组,线程还不能被销毁、停止、暂停、恢复或中断
Lock是一种初级的多线程同步的手段, 存在“locked”或“unlocked”两种状态,在两种状态之间可相互转换。
存在两个基本方法,acquire()和release(), 它俩在单个线程当中都是成对使用的。
存在如下状态,请求锁定 > 进入锁定池等待 > 获取锁 > 已锁定 > 释放锁。
有效利用lock的状态转换机制,可避免多个线程同时修改同一份数据。
Lock被创建时为 “unlocked” 状态:
- 当为 “unlocked“ 状态时,线程调用acquire()可获取这个lock并将lock状态转换成”locked“并立即返回,线程不会阻塞
- 当为 “unlocked” 状态时,某个线程调用release(), 程序会抛出RuntimeError异常
当为 “locked” 状态时,不被特定的线程拥有:
- 当为 ’locked’ 状态时,线程调用acquire()会阻塞自己,直到其他的线程将lock的状态变成unlocked;
- 当为 “locked” 状态时,线程调用release()方法,可释放1个lock, 则其他线程即可获取这个lock了
threading.Lock() 实现原始锁对象Lock的类 一旦1个线程获得1个Lock, 会阻塞随后尝试获得锁的线程,直到它被释放,且任何线程都可释放锁方法
| 方法 | 作用 |
|---|---|
| threading.Lock.acquire(blocking=True, timeout=-1) | 获得锁,如果lock是空闲的,则立即返回;如果lock已被其他线程占用了,则阻塞等待。 blocking=True : 阻塞,立即返回False,直到锁被释放,然后将锁锁定并返回True。 blocking=False: 将不会发生阻塞, timeout的值将被忽略 timeout > 0 : 只要无法获得锁,将最多阻塞timeout设定的秒数。 timeout = -1: 无限等待,直至获得锁。如果成功获得锁,则返回True,否则返回False(e.g. 发生超时) |
| threading.Lock.release | 释放锁,唤醒等待锁的线程。 当多个线程在acquire()等待状态转变为未锁定被阻塞,然后release()重置状态为未锁定时,只有1个线程能继续执行; 至于哪个等待线程继续执行没有定义,并且会根据实现而不同。 如果未锁定的锁调用时,会引发RuntimeError异常,没有返回值。 释放一个锁,这个方法可在任何线程中调用,不单止获得锁的线程。 |
| threading.Lock.locked() | 如果获得了锁,则返回真值。 |
- 多线程访问单一资源
多线程应用中,某个资源被多个线程共享访问,线程在线程函数执行前通过使用lock独占该资源,直至执行完成后,释放该Lock,则可确保排队变成单线程一个一个执行,即每次只有一个线程占用Lock。
e.g. 某个线程在使用打印机时,不允许其他线程向打印机输出。某个线程对某变量进行读取访问时,不允许其他线程同时对这个变量进行读取访问 - 多线程访问多资源
多个线程调用多个对象,而A线程调用A锁占用A对象,B线程调用B锁占用B对象,则A线程不能调用B对象,B线程不能调用A对象,于是一直等待,造成线程死锁。
\ 多个线程同时操作共享数据
import threading, time
def func(people, do):
print(people, 'ready to', do, time.ctime(time.time()))
time.sleep(1)
for i in range(3):
time.sleep(1)
print(people, do, 'hamburger', time.ctime(time.time()))
print(people, do, time.ctime(time.time()))
class TestThread(threading.Thread):
def __init__(self, people, name, do):
threading.Thread.__init__(self)
self.threadName = name
self.people = people
self.do = do
def run(self):
print('*'*5)
print('START thread: ', self.name, time.ctime(time.time()))
func(self.people, self.do)
print('END thread: ', self.name, time.ctime(time.time()), )
print('=' * 5)
print('let us start !')
--------------------------------------------------------------------
C:python34python.exe C:/Users/E910600/PycharmProjects/0705/test2.py
let us start !
*****
START thread: Thread-1 Mon Sep 27 10:24:39 2021
A ready to add Mon Sep 27 10:24:39 2021
*****
START thread: Thread-2 Mon Sep 27 10:24:39 2021
B ready to eat Mon Sep 27 10:24:39 2021
A add hamburger Mon Sep 27 10:24:41 2021
B eat hamburger Mon Sep 27 10:24:41 2021
A add hamburger Mon Sep 27 10:24:42 2021
B eat hamburger Mon Sep 27 10:24:42 2021
A add hamburger Mon Sep 27 10:24:43 2021
A add Mon Sep 27 10:24:43 2021
END thread: Thread-1 Mon Sep 27 10:24:43 2021
=====
B eat hamburger Mon Sep 27 10:24:43 2021
B eat Mon Sep 27 10:24:43 2021
END thread: Thread-2 Mon Sep 27 10:24:43 2021
=====
main thread ends
Process finished with exit code 0
使用Lock时
import threading, time
## 多个线程同时操作共享数据
def func(people, do):
print(people, 'ready to', do, time.ctime(time.time()))
time.sleep(1)
for i in range(3):
time.sleep(1)
print(people, do, 'hamburger', time.ctime(time.time()))
print(people, do, time.ctime(time.time()))
class TestThread(threading.Thread):
Lock = threading.Lock()
def __init__(self, people, name, do):
threading.Thread.__init__(self)
self.threadName = name
self.people = people
self.do = do
def run(self):
print('*'*5)
print('START thread: ', self.name, time.ctime(time.time()))
self.Lock.acquire()
func(self.people, self.do)
self.Lock.release()
print('END thread: ', self.name, time.ctime(time.time()), )
print('=' * 5)
print('let us start !')
--------------------------------------------------------------------
C:python34python.exe C:/Users/E910600/PycharmProjects/0705/test2.py
let us start !
*****
START thread: Thread-1 Mon Sep 27 10:33:20 2021
A ready to add Mon Sep 27 10:33:20 2021
*****
START thread: Thread-2 Mon Sep 27 10:33:20 2021
A add hamburger Mon Sep 27 10:33:22 2021
A add hamburger Mon Sep 27 10:33:23 2021
A add hamburger Mon Sep 27 10:33:24 2021
A add Mon Sep 27 10:33:24 2021
END thread: Thread-1 Mon Sep 27 10:33:24 2021
=====
B ready to eat Mon Sep 27 10:33:24 2021
B eat hamburger Mon Sep 27 10:33:26 2021
B eat hamburger Mon Sep 27 10:33:27 2021
B eat hamburger Mon Sep 27 10:33:28 2021
B eat Mon Sep 27 10:33:28 2021
END thread: Thread-2 Mon Sep 27 10:33:28 2021
=====
main thread ends
Process finished with exit code 0
2.
使用Lock且只请求一次
\ With lock = acquire & release,正常的lock对象不能请求多次,即使是由同一个线程请求也不例外。
\ 如果同一个调用链中的多个函数访问同一个锁,则会发生意外。
\ 如果期望在同一个线程的不同代码需要重新获得锁,则使用Rlock
import threading, time
class TestThread(threading.Thread):
def __init__(self, start=0):
threading.Thread.__init__(self)
self.Lock = threading.Lock()
self.value = start
def func(self):
print('*' * 5)
print('wait for lock', time.ctime(time.time()))
with self.Lock:
print(time.ctime(time.time()), 'Acquire Lock')
self.value += 1
print(self.value)
print('release lock', time.ctime(time.time()))
print('=' * 5)
def run(self):
print('*' * 10)
print('enter worker and then sleep 3 s', time.ctime(time.time()))
time.sleep(3)
self.func()
print('=' * 10)
if __name__ == '__main__':
addThread = TestThread()
for i in range(3):
t = threading.Thread(target=run, name=str(i), args=(addThread,))
t.start()
print('thread', t.getName(), time.ctime(time.time()))
t.join()
print('main thread ends')
--------------------------------------------------------------------
C:python34python.exe C:/Users/E910600/PycharmProjects/0705/test2.py
**********
thread 0 Mon Sep 27 10:48:28 2021
enter worker and then sleep 3 s Mon Sep 27 10:48:28 2021
*****
wait for lock Mon Sep 27 10:48:31 2021
Mon Sep 27 10:48:31 2021 Acquire Lock
1
release lock Mon Sep 27 10:48:31 2021
=====
==========
**********
thread 1 Mon Sep 27 10:48:31 2021
enter worker and then sleep 3 s Mon Sep 27 10:48:31 2021
*****
wait for lock Mon Sep 27 10:48:34 2021
Mon Sep 27 10:48:34 2021 Acquire Lock
2
release lock Mon Sep 27 10:48:34 2021
=====
==========
**********
thread 2 Mon Sep 27 10:48:34 2021
enter worker and then sleep 3 s Mon Sep 27 10:48:34 2021
*****
wait for lock Mon Sep 27 10:48:37 2021
Mon Sep 27 10:48:37 2021 Acquire Lock
3
release lock Mon Sep 27 10:48:37 2021
=====
==========
main thread ends
Process finished with exit code 0
使用Lock且请求同一Lock多次
import threading, time
class TestThread(threading.Thread):
def __init__(self, start=0):
threading.Thread.__init__(self)
self.Lock = threading.Lock()
self.value = start
def func(self):
print('*' * 5)
print('wait for lock', time.ctime(time.time()))
self.Lock.acquire()
print(time.ctime(time.time()), 'Acquire Lock')
self.value += 1
print(self.value, 'and sleep 3s ')
time.sleep(3)
self.Lock.acquire()
print(time.ctime(time.time()), 'Acquire Lock')
self.value += 1
print(self.value, 'and release lock')
print('release lock', time.ctime(time.time()))
print('=' * 5)
def run(self):
print('*' * 10)
print('enter worker and then sleep 3 s', time.ctime(time.time()))
time.sleep(3)
self.func()
print('=' * 10)
if __name__ == '__main__':
addThread = TestThread()
for i in range(3):
t = threading.Thread(target=run, name=str(i), args=(addThread,))
t.start()
print('thread', t.getName(), time.ctime(time.time()))
t.join()
print('main thread ends')
--------------------------------------------------------------------
C:python34python.exe C:/Users/E910600/PycharmProjects/0705/test2.py
**********
thread 0 Mon Sep 27 10:59:42 2021
enter worker and then sleep 3 s Mon Sep 27 10:59:42 2021
*****
wait for lock Mon Sep 27 10:59:45 2021
Mon Sep 27 10:59:45 2021 Acquire Lock
1 and sleep 3s
递归锁对象:RLock
概念
RLock是一个可被同一个线程多次获取的同步基元组件。
在内部,它在RLock的锁定 / 非锁定状态上附加了“所属线程“和”递归等级“的概念。
- 在锁定状态下,某些线程拥有锁;
- 在非锁定状态下,没有线程拥有它。
threading.RLock() RLock对象必须由获取它的线程释放,每获取一次必须相应地释放一次 一旦线程获取了RLock,同一个线程再次获取它将不阻塞方法
| 方法 | 作用 |
|---|---|
| threading.RLock.acquire | 当无参数调用时,如这个线程已获得锁,则递归级别+1,并立即返回; 否则如果其他线程拥有该锁,则阻塞至线程解锁,一旦锁被解锁则不属于任何线程。如果多个线程被阻塞,等待锁被解锁,一次只有1个线程能抢到锁的所有权。在这种情况下,没有返回值。 当有参数调用时, blocking=True,则执行与无参数调用时一样的操作,返回True。 blocking=False,则不进行阻塞。 timeout !=0, 只要无法获得锁,将最多阻塞timeout所指定描述,如已获得锁则返回True;如超时则返回False; |
| threading.RLock.release | 线程的acquire() / release()对可以嵌套。 只有最终release()(最外面的一对release())将锁解开,才能让其他线程继续处理acquire()阻塞,或者说其他线程才能获得资源。 释放锁,递归等级-1。 如减到0,则将锁重置为非锁定状态(不被任何线程拥有),并且如果其他线程正被阻塞着等待锁被解锁,则仅允许其中一个线程继续。 如自减后,递归等级仍然不为0,则锁保持锁定,仍由调用线程拥有。只有当前线程拥有锁才能调用这个方法,如果锁被释放后调用这个方法会引起RuntimeError异常。 |
| Lock | RLock |
|---|---|
| Lock对象处于acquire状态时,无法再被其它线程acquire,除非持有锁的线程先release锁 | RLock对象可多次被同一线程或其它线程acquire, release。RLock包含1个锁定池RLock和初始值为0的计数器Counter,每次成功调用acquire/release,计数器Counter将+1/-1,计时器Counter为0时锁处于未锁定状态。 |
| Lock对象可被任何线程释放 | RLock对象只能被持有的线程释放 |
| Lock对象不可被任何线程拥有 | RLock对象可被多个线程拥有 |
| 一个线程只能acquire一次Lock,一旦连续多次acquire会导致死锁 | 一个线程可acquire多次RLock,但是有多少次acquire() 就得有多少次release(),可解决部分死锁问题。 |
| 对一个对象锁定是很快的 | 对一个对象加RLock比加Lock慢 |
// RLock // 上面的程序中,2个线程同时访问共享资源abce时,当某一线程当前正在访问共享资源abce时,另一个线程将被阻塞,即无法访问共享资源。 // 当2个或多个线程试图访问相同的资源时,有效地阻塞彼此访问该资源,造成死锁,故此时不会生成任何输出。 from threading import Lock, RLock lock = Lock() # create 1 lock abce = 2 # initialize shared resource lock.acquire() # lock access shared resource abce = abce + 1 lock.acquire() # lock access shared resource will be trapped abce = abce + 2 lock.release() # release lock print(abce) -------------------------------------------------------------------- C:python34python.exe C:/Users/E910600/PycharmProjects/0705/test2.py使用RLock时
// RLock // 在此示例中,2个线程均未被阻止访问共享资源abce。 from threading import Lock, RLock lock = RLock() # create 1 lock abce = 2 # initialize shared resource lock.acquire() # lock access shared resource abce = abce + 1 lock.acquire() # lock access shared resource will be trapped abce = abce + 2 lock.release() # release lock print(abce) -------------------------------------------------------------------- C:python34python.exe C:/Users/E910600/PycharmProjects/0705/test2.py 5 Process finished with exit code 02. 未使用RLock时
// Lock
from threading import Lock, RLock, Thread, active_count, enumerate
import time
lock=Lock()
result=[]
def step1():
global result
if lock.acquire():
print('··· enter step 1 function')
print('> before step 1 function result = ', result)
result.append('step1')
time.sleep(2)
lock.release()
print('> step 1 function result = ', result)
def step2():
global result
if lock.acquire():
print('··· enter step 2 function')
print('> before step 2 function result = ', result)
result.append('step2')
time.sleep(2)
lock.release()
print('> step 2 function result = ', result)
def showresult():
if lock.acquire():
print('··· enter show result function')
print('> before show result function result = ', result)
step1()
step2()
lock.release()
print('> show result function result = ', result)
def clearresult():
global result
if lock.acquire():
print('··· enter clear result function')
print('> before clear result function result = ', result)
result = None
time.sleep(2)
lock.release()
print('clear result function result = ', result)
t1 = Thread(target=showresult, name='show result')
t2 = Thread(target=clearresult, name='clear result')
print('>>> before t1 and t2 start')
print(active_count())
print(enumerate())
print('^'*20)
t1.start()
print('>>> after t1 start but before t2 start')
print(active_count())
print(enumerate())
print('^'*20)
t2.start()
print('>>> after t1 and t2 start')
print(active_count())
print(enumerate())
print('^'*20)
--------------------------------------------------------------------
C:python34python.exe C:/Users/E910600/PycharmProjects/0705/test2.py
>>> before t1 and t2 start
1
[<_MainThread(MainThread, started 59188)>]
^^^^^^^^^^^^^^^^^^^^
··· enter show result function
>>> after t1 start but before t2 start
2
[, <_MainThread(MainThread, started 59188)>]
^^^^^^^^^^^^^^^^^^^^
> before show result function result = []
>>> after t1 and t2 start
3
[, , <_MainThread(MainThread, started 59188)>]
^^^^^^^^^^^^^^^^^^^^
Process finished with exit code -1
使用RLock时
// RLock
from threading import Lock, RLock, Thread, active_count, enumerate
import time
lock=RLock()
result=[]
def step1():
global result
if lock.acquire():
print('··· enter step 1 function')
print('> before step 1 function result = ', result)
result.append('step1')
time.sleep(2)
lock.release()
print('> step 1 function result = ', result)
def step2():
global result
if lock.acquire():
print('··· enter step 2 function')
print('> before step 2 function result = ', result)
result.append('step2')
time.sleep(2)
lock.release()
print('> step 2 function result = ', result)
def showresult():
if lock.acquire():
print('··· enter show result function')
print('> before show result function result = ', result)
step1()
step2()
lock.release()
print('> show result function result = ', result)
def clearresult():
global result
if lock.acquire():
print('··· enter clear result function')
print('> before clear result function result = ', result)
result = None
time.sleep(2)
lock.release()
print('clear result function result = ', result)
t1 = Thread(target=showresult, name='show result')
t2 = Thread(target=clearresult, name='clear result')
print('>>> before t1 and t2 start')
print(active_count())
print(enumerate())
print('^'*20)
t1.start()
print('>>> after t1 start but before t2 start')
print(active_count())
print(enumerate())
print('^'*20)
t2.start()
print('>>> after t1 and t2 start')
print(active_count())
print(enumerate())
print('^'*20)
--------------------------------------------------------------------
C:python34python.exe C:/Users/E910600/PycharmProjects/0705/test2.py
>>> before t1 and t2 start
1
[<_MainThread(MainThread, started 58080)>]
^^^^^^^^^^^^^^^^^^^^
··· enter show result function
> before show result function result = []
··· enter step 1 function
> before step 1 function result = []
>>> after t1 start but before t2 start
2
[<_MainThread(MainThread, started 58080)>, ]
^^^^^^^^^^^^^^^^^^^^
>>> after t1 and t2 start
3
[<_MainThread(MainThread, started 58080)>, , ]
^^^^^^^^^^^^^^^^^^^^
> step 1 function result = ['step1']
··· enter step 2 function
> before step 2 function result = ['step1']
> step 2 function result = ['step1', 'step2']
> show result function result = ['step1', 'step2']
··· enter clear result function
> before clear result function result = ['step1', 'step2']
clear result function result = None
Process finished with exit code 0
条件对象:Condition
概念
条件变量总是与某个类型的锁对象相关联,锁对象可通过传入获得,或在缺省的情况下自动创建。
当多个条件变量需共享同一个lock时,传入1个lock很有用。
Lock是条件对象的一部分,不必单独跟踪它。
条件变量服从上下文管理协议:
- 使用with语句会在它包围的代码块内获取关联的锁。
threading.Condition(lock) 一个条件变量对象Condition允许大于一个线程在其它线程锁通知(notify)之前进行 等待(wait)。 lock!=0, 则它必须为Lock或Rlock对象,并且它将被用作底层锁;否则将会创建新的RLock对象,将其作为底层锁方法
| 方法 | 作用 |
|---|---|
| threading.Condition.acquire() | 请求底层锁,返回底层锁相应方法的返回值。 |
| threading.Condition.release() | 释放底层锁,没有返回值。 |
| threading.Condition.wait(timeout=None) | 调用时若线程未获得Lock,将引发RuntimeError异常。 调用时若线程已获得Lock,它将释放底层锁,然后阻塞直到另一个线程调用同一个条件变量的notify/notify_all唤醒它,或直到timeout发生。 一旦被唤醒或超时,重新获得锁并返回。 timeout!=None时,它应当是一个浮点数,代表操作的超时时间。 当底层锁是RLock时,不会使用它的release()方法释放锁,因为当其被递归多次获取时,实际上可能无法解锁。 使用了RLock类的内部接口,即使多次递归获取它也能解锁它,然后再重新获取锁时,使用另一个内部接口来恢复递归。 未超时情况下,返回True;若超时,返回False。 |
| threading.condition.wait_for(predicate, timeout=None) | 等待至条件计算为真。predicate应该是一个可调用对象而且它的返回值可被解释为一个Bool值,可提供timeout参数给出最大等待时间,会重复调用wait()直到满足判断或超时。返回值是判断式最后一个返回值。而且如果方法发生超时会返回False。 |
| threading.Condition.notify(n=1) | 默认唤醒一个等待这个条件的线程。 调用这个方法的线程在未获得Lock的情况下,会引发RuntimeError异常。 在已获得Lock的情况下,最多唤醒n个正在等待这个条件变量的线程;如果没有线程在等待,则为一个空操作。 被唤醒的线程实际上不会返回它调用的wait(),直到它可以重新获得锁,因为notify()不会释放锁,只有它的调用者会这么做。 |
| threading.Condition.notify_all() | 调用这个方法的线程在已获得Lock的情况下,唤醒所有正在等待这个条件的线程,与notify相似,但并不只唤醒单一线程,而是唤醒所有等待线程。 否则,引发RuntimeError异常。 |
- 同步某些共享状态的权限
对状态的某些特定改变感兴趣的线程,它们重复调用 wait() 方法,直到看到所期望的改变发生。
对修改状态的线程,它们将当前状态改变为可能是等待者所期待的新状态后,调用 notify() 方法或者 notify_all() 方法。
\ child thread keep waiting until being notified by another thread
import threading, time
def funcA(condition):
print('*'*10)
print('A: Waiting', time.ctime(time.time()))
with condition: # thread.start() -> condition pass -> + 3s -> continue
print('A: to sleep 3 s', time.ctime(time.time()))
time.sleep(3)
print('A: Still waiting', time.ctime(time.time()))
condition.wait() # wait for 'notify' or 'notify all' and then continue
print('A: Got its Job', time.ctime(time.time()))
print('*' * 10)
def funcB(condition):
print('=' * 10)
print('B: will notify other threads soon', time.ctime(time.time()))
with condition:
print('B: to sleep 5 s', time.ctime(time.time()))
time.sleep(5)
print('B: is going to notify all other threads', time.ctime(time.time()))
condition.notifyAll() # after thread start, notify all start
print('B: should have notified all other threads', time.ctime(time.time()))
print('=' * 10)
condition = threading.Condition()
t1 = threading.Thread(name='t1', target=funcA, args=(condition, ))
t2 = threading.Thread(name='t2', target=funcA, args=(condition, ))
t3 = threading.Thread(name='t3', target=funcB, args=(condition, ))
print('before t1 start: ', 'count: ', threading.active_count(), ' enumerate:', threading.enumerate(), time.ctime(time.time()))
t1.start()
print('after t1 start: ', 'count: ', threading.active_count(), ' enumerate:', threading.enumerate(), time.ctime(time.time()))
print('before t2 start: ', 'count: ', threading.active_count(), ' enumerate:', threading.enumerate(), time.ctime(time.time()))
t2.start()
print('after t2 start: ', 'count: ', threading.active_count(), ' enumerate:', threading.enumerate(), time.ctime(time.time()))
print('before t3 start: ', 'count: ', threading.active_count(), ' enumerate:', threading.enumerate(), time.ctime(time.time()))
t3.start()
print('after t3 start: ', 'count: ', threading.active_count(), ' enumerate:', threading.enumerate(), time.ctime(time.time()))
--------------------------------------------------------------------
C:python34python.exe C:/Users/E910600/PycharmProjects/0705/test2.py
before t1 start: count: 1 enumerate: [<_MainThread(MainThread, started 52628)>] Mon Sep 27 14:50:04 2021
**********
A: Waiting Mon Sep 27 14:50:04 2021
after t1 start: count: 2 enumerate: [, <_MainThread(MainThread, started 52628)>] Mon Sep 27 14:50:04 2021
before t2 start: count: 2 enumerate: [, <_MainThread(MainThread, started 52628)>] Mon Sep 27 14:50:04 2021
A: to sleep 3 s Mon Sep 27 14:50:04 2021
**********
A: Waiting Mon Sep 27 14:50:04 2021
after t2 start: count: 3 enumerate: [, , <_MainThread(MainThread, started 52628)>] Mon Sep 27 14:50:04 2021
before t3 start: count: 3 enumerate: [, , <_MainThread(MainThread, started 52628)>] Mon Sep 27 14:50:04 2021
==========
B: will notify other threads soon Mon Sep 27 14:50:04 2021
after t3 start: count: 4 enumerate: [, , <_MainThread(MainThread, started 52628)>, ] Mon Sep 27 14:50:04 2021
A: Still waiting Mon Sep 27 14:50:07 2021
A: to sleep 3 s Mon Sep 27 14:50:07 2021
A: Still waiting Mon Sep 27 14:50:10 2021
B: to sleep 5 s Mon Sep 27 14:50:10 2021
B: is going to notify all other threads Mon Sep 27 14:50:15 2021
B: should have notified all other threads Mon Sep 27 14:50:15 2021
==========
A: Got its Job Mon Sep 27 14:50:15 2021
**********
A: Got its Job Mon Sep 27 14:50:15 2021
**********
Process finished with exit code 0
信号量对象:Semaphore
概念
信号量是由操作系统管理的一种抽象数据类型,用于在多线程中同步对共享资源的使用或临界区的访问,比如标明当前的共享资源可以有多少并发读取;其内部管理一个原子性计数器,指定可同步的线程数。
信号量的操作有2个函数,即acquire()和release().
- 每当线程想要读取关联了信号量的共享资源时,需调用acquire(), 此操作减少信号量计数器的值。
- 如计数器值非负,则分配给该线程权限;
如计数器值为负,则线程被挂起且其他线程停止访问信号量,直到有其他线程释放资源- 如线程不再需要该共享资源,必须通过release()释放。如此,计数器值增加,在信号量等待队列中排在最前面的线程会拿到共享资源的权限。
信号量被初始化为0, 此信号量唯一的目的是同步2个或多个线程。当线程必须并行运行时,需要信号量同步。
semaphore = threading.Semaphore(0) # 可选参数value赋予内部计数器初始值,默认值为1。若被赋予小于0的值,将引发ValueError异常。
信号量的一个特殊用法是互斥量。
互斥量是初始值为1的信号量,可以实现数据、资源的互斥访问。
信号量在支持多线程的编程语言中依然应用很广,然而这可能导致死锁的情况。例如,现在有一个线程t1先等待信号量s1,然后等待信号量s2,而线程t2会先等待信号量s2,然后再等待信号量s1,这样就可能会发生死锁,导致t1等待s2,但是t2在等待s1。
信号量的等待和通知操作如果都是原子的,则信号量机制无明显问题。
如并非原子的,或两个操作有一个终止了,会导致糟糕的情况。
举个例子,假设此时有两个并发的线程,都在等待一个信号量,目前信号量计数器值为1。假设线程A将信号量计数器的值从1减到0,这时候控制权又切到了B,线程B将信号量计数器的值从0减到-1,并在这里被挂起等待,这时控制权回到线程A,信号量已成负值,于是线程A也在等待。
如此,即使当时的信号量是可以让线程访问资源的,但是因为非原子操作导致所有线程都在等待状态。
信号量对象支持上下文管理协议
| 类 | 方法 | 作用 |
|---|---|---|
| threading.Semaphore | acquire(blocking=True, timeout=None) | 获取(acquire)信号量。 在默认参数下调用时, 如果在进入时内部计时器的值大于零则将其减一并立即返回True; 如果在进入时内部计数器的值为零,则将会阻塞直到被对release()的调用唤醒,一旦被唤醒并且计数器的值大于零则将其减一并立即返回True。 每次对release()的调用将只唤醒一个线程。线程被唤醒的次序是不可确定的。 当blocking=False, 则不进行阻塞。 如果一个无参数调用将要阻塞并立即返回False; 在其它情况下,执行与无参数调用时一样的操作,然后返回True。 当timeout != None, 则其阻塞最多timeout秒,在超时后若仍未能成功完成获取则将返回False,而其它情况下返回True。 |
| release() | 释放(release)信号量。 将内部计时器的值+1。 当计时器原先的值为0且有其它线程正在等待它再次大于0时,唤醒正在等待的线程。 | |
| threading.BoundedSemaphore | 该类实现有界信号量。 有界信号量通过检查以确保它当前的值不会超过初始值。 如果超过初始值,会引发ValueError异常。 大多数情况下,信号量用于保护数量有限的资源。 如果信号量被释放次数过多,则表明出现错误。 |
- 连接池,线程池,MySQL的有连接池,同一时间有多少个并发,就能连多少个连接。
- python不会默认你启动多少个线程,但是启动的线程越多,会把系统、程序拉的越慢。这里可以同一时间放100个线程进来,这就是semaphore
// Semaphore: 这5个中如果有3个完成,会再放3个进去。不会等5个都完成。
// 每release一个就放进去一个,出来几个放进去几个。
// 类似于停车场的停车位固定,当满员时,每出来一个,再进去一个。
import time
from threading import Thread, Semaphore, BoundedSemaphore, active_count, enumerate
def func(n):
Semaphore.acquire() # 加信号量锁
print(n, " 33[31;1m now, enter fun 33[0m", time.ctime(time.time()))
time.sleep(2)
Semaphore.release() # 释放信号量锁
print(" 33[31;1m release n: 33[0m", n)
if __name__=='__main__':
Semaphore = BoundedSemaphore(3) # 最多允许5个线程同时运行 (Bounded: 绑定;Semaphore: 信号量)
for i in range(6): # 此处总共6个线程,0,1,2,3,4,5
t = Thread(target=func, args=(i,))
print(i, ' before start: active count & enumerate : ',active_count(), enumerate())
t.start()
print(i, 'after start and end: active count & enumerate : ', active_count(), enumerate())
print()
while active_count() != 1:
pass
else:
print(" 33[31;1m --- all threads done --- 33[0m")
--------------------------------------------------------------------
C:python34python.exe C:/Users/E910600/PycharmProjects/0705/test2.py
0 before start: active count & enumerate : 1 [<_MainThread(MainThread, started 52148)>]
0 now, enter fun Fri Sep 24 14:27:50 2021
0 after start and end: active count & enumerate : 2 [, <_MainThread(MainThread, started 52148)>]
1 before start: active count & enumerate : 2 [, <_MainThread(MainThread, started 52148)>]
1 now, enter fun Fri Sep 24 14:27:50 2021
1 after start and end: active count & enumerate : 3 [, , <_MainThread(MainThread, started 52148)>]
2 before start: active count & enumerate : 3 [, , <_MainThread(MainThread, started 52148)>]
2 now, enter fun Fri Sep 24 14:27:50 2021
2 after start and end: active count & enumerate : 4 [, , <_MainThread(MainThread, started 52148)>, ]
3 before start: active count & enumerate : 4 [, , <_MainThread(MainThread, started 52148)>, ]
3 after start and end: active count & enumerate : 5 [, , , <_MainThread(MainThread, started 52148)>, ]
4 before start: active count & enumerate : 5 [, , , <_MainThread(MainThread, started 52148)>, ]
4 after start and end: active count & enumerate : 6 [, , <_MainThread(MainThread, started 52148)>, , , ]
5 before start: active count & enumerate : 6 [, , <_MainThread(MainThread, started 52148)>, , , ]
5 after start and end: active count & enumerate : 7 [, , <_MainThread(MainThread, started 52148)>, , , , ]
release n: 2
release n: 0
3 now, enter fun Fri Sep 24 14:27:52 2021
release n: 1
5 now, enter fun Fri Sep 24 14:27:52 2021
4 now, enter fun Fri Sep 24 14:27:52 2021
release n: 3
release n: 5
release n: 4
--- all threads done ---
Process finished with exit code 0
2.
// 有2个线程P和C,它们使用共同的资源,即item. P的任务是创建item并赋值,C的任务是消费item。在C未被创建出来时C会一直等待直到item生产出来,P会通知C可以开始消费item了。
import time, random
from threading import Thread, Semaphore, BoundedSemaphore, active_count, enumerate
# The optional argument gives the initial value for the internal
# counter;
# it defaults to 1.
# If the value given is less than 0, ValueError is raised.
semaphore = Semaphore(0)
def C():
print("C Waiting", time.ctime(time.time()))
# Acquire a semaphore
semaphore.acquire()
print("C Entered")
# The consumer have access to shared resource
print("C Notify : consumed item number %s " % item, time.ctime(time.time()))
def P():
global item
print("P Entered", time.ctime(time.time()))
time.sleep(10)
print('P has waited for 10 s', time.ctime(time.time()))
# create a random item
item = random.randint(0, 1000)
print("P Notify : produced item number %s" % item, time.ctime(time.time()))
# Release a semaphore, incrementing the internal counter by 1.
# When it is zero on entry and another thread is waiting for it
# to become larger than zero again, wake up that thread.
semaphore.release()
if __name__ == '__main__':
t1 = Thread(target=P)
t2 = Thread(target=C)
print('before t1/t2 start: ', active_count(), enumerate(), time.ctime(time.time()))
print()
t1.start()
print('after t1 start but t2 not start yet: ', active_count(), enumerate(), time.ctime(time.time()))
print()
print('--- Main Thread In Progress')
print()
t2.start()
print('after t1/t2 start: ', active_count(), enumerate(), time.ctime(time.time()))
t1.join()
t2.join()
while active_count() != 1:
pass
else:
print()
print('--- Main Thread Stopped.')
--------------------------------------------------------------------
C:python34python.exe C:/Users/E910600/PycharmProjects/0705/test2.py
before t1/t2 start: 1 [<_MainThread(MainThread, started 19664)>] Fri Sep 24 17:21:18 2021
P Entered Fri Sep 24 17:21:18 2021
after t1 start but t2 not start yet: 2 [<_MainThread(MainThread, started 19664)>, ] Fri Sep 24 17:21:18 2021
--- Main Thread In Progress
C Waiting Fri Sep 24 17:21:18 2021
after t1/t2 start: 3 [<_MainThread(MainThread, started 19664)>, , ] Fri Sep 24 17:21:18 2021
P has waited for 10 s Fri Sep 24 17:21:28 2021
P Notify : produced item number 986 Fri Sep 24 17:21:28 2021
C Entered
C Notify : consumed item number 986 Fri Sep 24 17:21:28 2021
--- Main Thread Stopped.
Process finished with exit code 0
3.
Without Semaphore
// Without Sempaphore,主机执行密集型任务,容易宕机
import threading, time
def func(n):
print('*' * 5)
print(threading.current_thread().getName(), 'entered', time.ctime(time.time()))
time.sleep(3) # thread doing its job, after job done, release
print(threading.current_thread().getName(), 'after sleeping 3 s, job done', time.ctime(time.time()))
print(threading.current_thread().getName(), ' current thread count', threading.active_count())
print('+' * 5)
if __name__=='__main__':
for i in range(8):
t1 = threading.Thread(target=func, args=(i,))
t1.start()
print(t1.getName(), 'starts and active count:', threading.active_count())
time.sleep(10)
print('=' * 5)
print(threading.current_thread().getName(), 'current thread count: ', threading.active_count())
--------------------------------------------------------------------
C:python34python.exe C:/Users/E910600/PycharmProjects/0705/test2.py
*****
Thread-1 starts and active count: 2
Thread-1 entered Sun Sep 26 11:23:11 2021
*****
Thread-2 entered Sun Sep 26 11:23:11 2021
Thread-2 starts and active count: 3
*****
Thread-3 entered Sun Sep 26 11:23:11 2021
Thread-3 starts and active count: 4
*****
Thread-4 entered Sun Sep 26 11:23:11 2021
Thread-4 starts and active count: 5
*****
Thread-5 entered Sun Sep 26 11:23:11 2021
Thread-5 starts and active count: 6
*****
Thread-6 entered Sun Sep 26 11:23:11 2021
Thread-6 starts and active count: 7
*****
Thread-7 entered Sun Sep 26 11:23:11 2021
Thread-7 starts and active count: 8
*****
Thread-8 entered Sun Sep 26 11:23:11 2021
Thread-8 starts and active count: 9
Thread-2 after sleeping 3 s, job done Sun Sep 26 11:23:14 2021
Thread-2 current thread count 9
+++++
Thread-3 after sleeping 3 s, job done Sun Sep 26 11:23:14 2021
Thread-1 after sleeping 3 s, job done Sun Sep 26 11:23:14 2021
Thread-3 current thread count 8
Thread-1 current thread count 8
+++++
Thread-4 after sleeping 3 s, job done Sun Sep 26 11:23:14 2021
Thread-6 after sleeping 3 s, job done Sun Sep 26 11:23:14 2021
Thread-6 current thread count 8
+++++
Thread-4 current thread count 7
+++++
Thread-5 after sleeping 3 s, job done Sun Sep 26 11:23:14 2021
Thread-5 current thread count 7
+++++
Thread-8 after sleeping 3 s, job done Sun Sep 26 11:23:14 2021
+++++
Thread-8 current thread count 3
+++++
Thread-7 after sleeping 3 s, job done Sun Sep 26 11:23:14 2021
Thread-7 current thread count 2
+++++
=====
MainThread current thread count: 1
Process finished with exit code 0
With Semaphore
// With Sempaphore,主机执行密集型任务时,为程序添加Semaphore计时器,
// 限制一个时间点内的线程数量
import threading, time
Semaphore = threading.Semaphore(3) # Counter initial value = 5
def func(n):
print('*' * 5)
print(threading.current_thread().getName(), 'entered')
if Semaphore.acquire(): # acquire
print(threading.current_thread().getName(), 'acquired', time.ctime(time.time()))
time.sleep(3) # thread doing its job, after job done, release
print(threading.current_thread().getName(), 'after sleeping 3 s, job done', time.ctime(time.time()))
print(threading.current_thread().getName(), 'not released yet and current thread count', threading.active_count())
Semaphore.release() # release
print(threading.current_thread().getName(), ' released and current thread counts: ', threading.active_count())
print('+' * 5)
if __name__=='__main__':
for i in range(8):
t1 = threading.Thread(target=func, args=(i,))
t1.start()
print(t1.getName(), 'starts and active count:', threading.active_count())
time.sleep(10)
print('=' * 5)
print(threading.current_thread().getName(), 'current thread count: ', threading.active_count())
--------------------------------------------------------------------
C:python34python.exe C:/Users/E910600/PycharmProjects/0705/test2.py
*****
Thread-1 starts and active count: 2
Thread-1 entered
Thread-1 acquired Sun Sep 26 11:20:24 2021
*****
Thread-2 starts and active count: 3
Thread-2 entered
Thread-2 acquired Sun Sep 26 11:20:24 2021
*****
Thread-3 starts and active count: 4
Thread-3 entered
Thread-3 acquired Sun Sep 26 11:20:24 2021
*****
Thread-4 entered
Thread-4 starts and active count: 5
*****
Thread-5 entered
Thread-5 starts and active count: 6
*****
Thread-6 entered
Thread-6 starts and active count: 7
*****
Thread-7 entered
Thread-7 starts and active count: 8
*****
Thread-8 entered
Thread-8 starts and active count: 9
Thread-3 after sleeping 3 s, job done Sun Sep 26 11:20:27 2021
Thread-3 not released yet and current thread count 9
Thread-3 released and current thread counts: 9
+++++
Thread-2 after sleeping 3 s, job done Sun Sep 26 11:20:27 2021
Thread-1 after sleeping 3 s, job done Sun Sep 26 11:20:27 2021
Thread-4 acquired Sun Sep 26 11:20:27 2021
Thread-2 not released yet and current thread count 8
Thread-2 released and current thread counts: 8
+++++
Thread-1 not released yet and current thread count 8
Thread-1 released and current thread counts: 8
+++++
Thread-5 acquired Sun Sep 26 11:20:27 2021
Thread-6 acquired Sun Sep 26 11:20:27 2021
Thread-6 after sleeping 3 s, job done Sun Sep 26 11:20:30 2021
Thread-6 not released yet and current thread count 6
Thread-6 released and current thread counts: 6
+++++
Thread-7 acquired Sun Sep 26 11:20:30 2021
Thread-5 after sleeping 3 s, job done Sun Sep 26 11:20:30 2021
Thread-4 after sleeping 3 s, job done Sun Sep 26 11:20:30 2021
Thread-4 not released yet and current thread count 5
Thread-4 released and current thread counts: 5
+++++
Thread-5 not released yet and current thread count 5
Thread-5 released and current thread counts: 5
+++++
Thread-8 acquired Sun Sep 26 11:20:30 2021
Thread-7 after sleeping 3 s, job done Sun Sep 26 11:20:33 2021
Thread-7 not released yet and current thread count 3
Thread-7 released and current thread counts: 3
+++++
Thread-8 after sleeping 3 s, job done Sun Sep 26 11:20:33 2021
Thread-8 not released yet and current thread count 2
Thread-8 released and current thread counts: 2
+++++
=====
MainThread current thread count: 1
Process finished with exit code 0
事件对象:Event
概念
threading.Event() 线程之间通信的最简单机制之一:一个事件对象管理一个内部标志 一个线程发出事件信号,而其它线程等待该信号 使用set()方法将内部标志设为True,调用clear()方法将其设为False,调用wait()方法将其进入阻塞直到标志为True方法
| 方法 | 作用 |
|---|---|
| threading.Event.is_set() | 当且仅当内部旗帜为时返回True |
| threading.Event.clear() | 将内部标志设置为True,所有正在等待这个事件的线程将被唤醒,调用wait()方法的线程不会被阻塞。 |
| threading.Event.wait(timeout=None) | 阻塞线程直到内部变量为True,如果调用时内部标志为True, 将立即返回,否则阻塞线程,直到调用set()方法将标志设置为True或者发生可选的超时。除非发生超时,则返回False。 timeout != None时,它应当是一个浮点数,代表操作的超时时间,以秒为单位(可以为小数)。 |
import threading, time
event = threading.Event()
def func():
print('*'*10)
print(threading.current_thread().getName(), 'waiting for event:', event.is_set(), time.ctime(time.time()))
event.wait() # wait for event signal
print(threading.current_thread().getName(), 'received:', event.is_set(), time.ctime(time.time()))
print('*' * 10)
if __name__ == '__main__':
for i in range(3):
t = threading.Thread(target=func, name=str(i))
print('before ', t.getName(), 'start:', time.ctime(time.time()))
t.start()
print('after', t.getName(), 'start:', time.ctime(time.time()))
print(threading.current_thread().getName(), 'sleep 3 s', time.ctime(time.time()))
time.sleep(3)
print(threading.current_thread().getName(), 'will set event', time.ctime(time.time()))
event.set() # set event signal
--------------------------------------------------------------------
C:python34python.exe C:/Users/E910600/PycharmProjects/0705/test2.py
before 0 start: Mon Sep 27 15:36:59 2021
**********
0 waiting for event: False Mon Sep 27 15:36:59 2021
after 0 start: Mon Sep 27 15:36:59 2021
before 1 start: Mon Sep 27 15:36:59 2021
**********
1 waiting for event: False Mon Sep 27 15:36:59 2021
after 1 start: Mon Sep 27 15:36:59 2021
before 2 start: Mon Sep 27 15:36:59 2021
**********
2 waiting for event: False Mon Sep 27 15:36:59 2021
after 2 start: Mon Sep 27 15:36:59 2021
MainThread sleep 3 s Mon Sep 27 15:36:59 2021
MainThread will set event Mon Sep 27 15:37:02 2021
2 received: True Mon Sep 27 15:37:02 2021
**********
1 received: True Mon Sep 27 15:37:02 2021
**********
0 received: True Mon Sep 27 15:37:02 2021
**********
Process finished with exit code 0
2.
import threading, time
def funcA(event:threading.Event, n=10):
print('*'*10)
print(threading.current_thread().getName(), 'starting working', time.ctime(time.time()))
count = 0
while True:
time.sleep(1)
count += 1
print('count: ', count, time.ctime(time.time()))
if count > n:
event.set()
break
print('count', count, ' > n ', n, 'While ends', time.ctime(time.time()))
print('*' * 10)
def funcB(event:threading.Event):
print(threading.current_thread().getName(), 'is waiting', time.ctime(time.time()))
event.wait()
print(threading.current_thread().getName(), 'receives event signal and do not have to wait now')
print('Done', time.ctime(time.time()))
Event = threading.Event()
A = threading.Thread(target=funcA, name='Thread-1', args=(Event, 5))
B = threading.Thread(target=funcB, name='Thread-2', args=(Event,))
A.start()
print(A.getName(), 'start', time.ctime(time.time()))
B.start()
print(B.getName(), 'start', time.ctime(time.time()))
print(threading.current_thread().getName(), 'Now sleep 8 s', time.ctime(time.time()))
time.sleep(8)
print('Main Thread Ends.', time.ctime(time.time()))
A.join()
B.join()
--------------------------------------------------------------------
C:python34python.exe C:/Users/E910600/PycharmProjects/0705/test2.py
**********
Thread-1 starting working Mon Sep 27 17:23:39 2021
Thread-1 start Mon Sep 27 17:23:39 2021
Thread-2 is waiting Mon Sep 27 17:23:39 2021
Thread-2 start Mon Sep 27 17:23:39 2021
MainThread Now sleep 8 s Mon Sep 27 17:23:39 2021
count: 1 Mon Sep 27 17:23:40 2021
count: 2 Mon Sep 27 17:23:41 2021
count: 3 Mon Sep 27 17:23:42 2021
count: 4 Mon Sep 27 17:23:43 2021
count: 5 Mon Sep 27 17:23:44 2021
count: 6 Mon Sep 27 17:23:45 2021
count 6 > n 5 While ends Mon Sep 27 17:23:45 2021
**********
Thread-2 receives event signal and do not have to wait now
Done Mon Sep 27 17:23:45 2021
Main Thread Ends. Mon Sep 27 17:23:47 2021
Process finished with exit code 0
实例化
1.
import threading, time
from decimal import Decimal
def func(x: int, y:int):
print('func result: ', x+y, time.ctime(time.time()))
class TestThread(object):
def __init__(self, delay, f, args, kwargs):
self.delay = delay
self.f = f
self.args = args
self.kwargs = kwargs
self.event = threading.Event()
def start(self):
threading.Thread(target=self.run, name='Thread-func').start()
def cancel(self):
self.event.set()
is_set = self.event.is_set()
return is_set
def run(self):
print(threading.current_thread().getName(), 'is waiting', time.ctime(time.time()))
start = time.time()
self.event.wait(self.delay)
end = time.time()
if not self.event.is_set(): # is_set() = False
# if no self.event.wait(self.delay)
self.f(self.args, self.kwargs) # def func(x=args, y=kwargs)
print(threading.current_thread().getName(), 'has waited time: ', Decimal(end-start).quantize(Decimal("0")), time.ctime(time.time()))
self.event.set()
if self.event.is_set(): # is_set() = True
print(threading.current_thread().getName(), 'receives event and do not have to wait now', time.ctime(time.time()))
t = TestThread(5,func,3,1)
thread = t.start()
print('='*10)
print(threading.current_thread().getName(), 'is waiting', time.ctime(time.time()))
event = threading.Event()
start = time.time()
event.wait(10)
end = time.time()
print(threading.current_thread().getName(), 'has waited time', Decimal(end-start).quantize(Decimal("0")), time.ctime(time.time()))
if not event.is_set():
print(threading.current_thread().getName(), 'is waiting', time.ctime(time.time()))
is_set = t.cancel()
if is_set:
print(threading.current_thread().getName(), 'receives event and do not have to wait now', time.ctime(time.time()))
if threading.active_count() == 1:
print(threading.current_thread().getName(), 'Done.')
--------------------------------------------------------------------
C:python34python.exe C:/Users/E910600/PycharmProjects/0705/test2.py
Thread-func is waiting Mon Sep 27 19:03:10 2021
==========
MainThread is waiting Mon Sep 27 19:03:10 2021
func result: 4 Mon Sep 27 19:03:15 2021
Thread-func has waited time: 5 Mon Sep 27 19:03:15 2021
Thread-func receives event and do not have to wait now Mon Sep 27 19:03:15 2021
MainThread has waited time 10 Mon Sep 27 19:03:20 2021
MainThread is waiting Mon Sep 27 19:03:20 2021
MainThread receives event and do not have to wait now Mon Sep 27 19:03:20 2021
MainThread Done.
Process finished with exit code 0
定时器对象:Timer
栅栏对象:Barrier
在with语句中使用锁、条件和信号量
参考文章
RLock:
Python中Lock和Rlock
python中的RLock和Lock
Semaphore
- 使用信号量进行线程同步.
- 【python】-- 信号量(Semaphore)、event(红绿灯例子)
- Python3学习(二十四):python中的线程之semaphore信号量
- Python 中Semaphore 信号量对象、Event事件、Condition
Event
- 使用信号量进行线程同步.
- 【python】-- 信号量(Semaphore)、event(红绿灯例子)



