栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

Python | threading

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Python | threading

Threading --- 基于线程的并行
  • 线程 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 概念

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对象,于是一直等待,造成线程死锁。
示例 1. 未使用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):
    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 V.S RLock
LockRLock
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慢
示例 1. 未使用RLock时
// 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 0
2. 未使用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() 方法。
示例 1.
\ 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.Semaphoreacquire(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
示例 1.
// 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时,它应当是一个浮点数,代表操作的超时时间,以秒为单位(可以为小数)。
示例 函数传递 1.
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

  1. 使用信号量进行线程同步.
  2. 【python】-- 信号量(Semaphore)、event(红绿灯例子)
  3. Python3学习(二十四):python中的线程之semaphore信号量
  4. Python 中Semaphore 信号量对象、Event事件、Condition

Event

  1. 使用信号量进行线程同步.
  2. 【python】-- 信号量(Semaphore)、event(红绿灯例子)
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/269170.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号