专栏首页dodott的专栏python--线程同步原语
原创

python--线程同步原语

Threading模块是python3里面的多线程模块,模块内集成了许多的类,其中包括Thread,Condition,Event,Lock,Rlock,Semaphore,Timer等等。下面这篇文章主要通过案例来说明其中的Event和Segmaphore(Boundedsegmaphore)的使用。关于Lock的使用可以移步到我之前写的文章python同步原语--线程锁。

Event

Event类内部保存着一个flags参数,标志事件的等待与否。

Event类实例函数

1. set() 将flags设置为True,事件停止阻塞

2. clear()  将flags重新设置为False,删除flags,事件重新阻塞

3. wait() 将事件设置为等待状态

4.is_set()判断flags是否被设置,如果被设置返回True,否则返回False

(1)单个事件等待其他事件的发生

具体代码:

from time import ctime,sleep
event = Event()

def event_wait():
    print(ctime())
    event.wait()
    print('这是event_wait方法中的时间',ctime())

def event_set(n):
    sleep(n)
    event.set()
    print('这是event_set方法中的时间', ctime())

thread1 = Thread(target=event_wait)
thread2 = Thread(target=event_set,args=(3,))

thread1.start()
thread2.start()

结果:

Sat Nov 17 10:01:05 2018
这是event_wait方法中的时间 Sat Nov 17 10:01:08 2018
这是event_set方法中的时间  Sat Nov 17 10:01:08 2018

(2)多个事件先后发生

下面以赛跑来作为例子。假设5条跑道上,每条跑道各有一名运动员,分别为ABCDE。

具体代码:

from threading import Event
from  threading import Thread
import threading

event = Event()

def do_wait(athlete):
    racetrack = threading.current_thread().getName()
    print('%s准备就绪' % racetrack)
    event.wait()
    print('%s听到枪声,起跑!'%athlete)

thread1 = Thread(target=do_wait,args=("A",))
thread2 = Thread(target=do_wait,args=("B",))
thread3 = Thread(target=do_wait,args=("C",))
thread4 = Thread(target=do_wait,args=("D",))
thread5 = Thread(target=do_wait,args=("E",))

threads = []
threads.append(thread1)
threads.append(thread2)
threads.append(thread3)
threads.append(thread4)
threads.append(thread5)

for th in threads:
    th.start()

event.set()  #这个set()方法很关键,同时对5个线程中的event进行set操作

结果:

Thread-1准备就绪
Thread-2准备就绪
Thread-3准备就绪
Thread-4准备就绪
Thread-5准备就绪
E听到枪声,起跑!
A听到枪声,起跑!
B听到枪声,起跑!
D听到枪声,起跑!
C听到枪声,起跑!

可以看出多个线程中event的set()是随机的,其内部的实现是因为一个notify_all()方法。这个方法会一次性释放所有锁住的事件,哪个线程先抢到线程运行的时间片,就先释放锁。

之所以能够只调用一个set()函数就可以实现所有event的退出阻塞,是因为event.wait()是在线程内部实现的,而set()函数是在进程中调用,python多线程共享一个进程内存空间。如果是在不同进程中调用这两个函数则无法实现。

BoundedSegmaphore

如果在主机执行IO密集型任务的时候再执行这种短时间内完成大量任务(多线程)的程序时,计算机就有很大可能会宕机。

这时候就可以为这段程序添加一个计数器(counter)功能,来限制一个时间点内的线程数量。当每次进行IO操作时,都需要向segmaphore请求资源(锁),如果没有请求到,就阻塞等待,请求成功才就像执行任务。

BoundedSegmaphore和Segmaphore的区别

BoundedSegmaphore请求的锁数量固定为传入参数,而Segmaphore请求的锁数量可以超过传入的参数。

主要函数:

1. acquire()  请求锁

2. release()   释放锁

下面以一个租房的例子来说明这种固定锁数量的机制。假设一家小公寓有6间房,原本有2个住户在住着。

具体代码实现:

from threading import BoundedSemaphore,Lock,Thread
from time import sleep
from random import randrange

lock = Lock()
num = 6
hotel = BoundedSemaphore(num)

def logout():
    lock.acquire()
    print('I want to logout')
    print('A customer logout...')
    try:
        hotel.release()
        print('Welcome again')
    except ValueError:
        print('Sorry,wait a moment.')
    lock.release()

def login():
    lock.acquire()
    print('I want to login')
    print('A customer login...')
    if hotel.acquire(False):
        print('Ok,your room number is...')
    else:
        print('Sorry,our hotel is full')
    lock.release()

#房东
def producer(loops):
    for i in range(loops):
        logout()
        print('还剩%s' % hotel._value, '房间')
        sleep(randrange(2))
#租客
def consumer(loops):
    for i in range(loops):
        login()
        print('还剩%s' % hotel._value, '房间')
        sleep(randrange(2))
def main():
    print('Start')
    room_num = hotel._value
    print('The hotel is full with %s room'%room_num)
    #原本有2个住户
    hotel.acquire()
    hotel.acquire()
    thread1 = Thread(target=producer,args=(randrange(2,8),))
    thread2 = Thread(target=consumer,args=(randrange(2,8),))
    thread1.start()
    thread2.start()

if __name__ == '__main__':
    main()

结果:

The hotel is full with 6 room
I want to logout
A customer logout...
Welcome again
还剩5 房间
I want to logout
A customer logout...
Welcome again
还剩6 房间
I want to login
A customer login...
Ok,your room number is...
还剩5 房间
I want to login
A customer login...
Ok,your room number is...
还剩4 房间

可以看出,房间数目永远不会超过6,因为_value值(BoundedSegmaphore内部的计数器counter)一定是传入的参数6。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • python--线程同步原语

    Threading模块是python3里面的多线程模块,模块内集成了许多的类,其中包括Thread,Condition,Event,Lock,Rlock,Sem...

    dodott
  • mybatis

    MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集...

    dodott
  • 盒子端 CSS 动画性能提升研究

    不同于传统的 PC Web 或者是移动 WEB,在客厅盒子端,接大屏显示器下,许多能流畅运行于 PC 端、移动端的 Web 动画,受限于硬件水平,在盒子端的表现...

    dodott
  • python--线程同步原语

    Threading模块是python3里面的多线程模块,模块内集成了许多的类,其中包括Thread,Condition,Event,Lock,Rlock,Sem...

    dodott
  • 中文文本相似度计算工具集

    作者 | fendouai 编辑 | 磐石 出品 | 磐创AI技术团队 ---- 【磐创AI导读】:前两篇文章中我们介绍了一些机器学习不错的项目合集和深度学习入...

    磐创AI
  • 【大咖说】工信部副部长:工业互联网成制造业转型关键

    导读:在第十六届中国经济论坛上,工信部副部长陈肇雄指出,当前我国经济传统动力衰减,制造业供给结构错配问题也日益凸显,急需利用网络化、信息化手段加快推动制造业结...

    钱塘数据
  • 必看,10篇定义计算机视觉未来的论文

    导语:如果你没能参加 CVPR 2019 , 别担心。本文列出了会上人们最为关注的 10 篇论文,覆盖了 DeepFakes(人脸转换), Facial Rec...

    AI科技大本营
  • 【DB笔试面试841】在Oracle中,如何跟踪tnsping过程?

    sqlnet是oracle提供的与网络层面交互的一个工具,比如如何解析客户端发起的连接,如何对客户端发起的连接进行辨别,如何对客户端连接进行阻隔限制,或者启用日...

    小麦苗DBA宝典
  • Python|实例方法,类方法,静态方法

    周五的时候修改了一点代码(确定不是bug),对Python 部分语法知识都生疏了,重新学习类中的方法。本章主要介绍python 类中的三种方法:实例方法,类方法...

    用户1278550
  • 多表查询经典例子

    create table students (sid char(8) primary key not null comment ‘学号’,name varcha...

    苦咖啡

扫码关注云+社区

领取腾讯云代金券