PHP前端开发

python中线程同步原语的代码示例

百变鹏仔 1个月前 (01-23) #Python
文章标签 示例

本篇文章给大家带来的内容是关于python中线程同步原语的代码示例,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

Threading模块是python3里面的多线程模块,模块内集成了许多的类,其中包括Thread,Condition,Event,Lock,Rlock,Semaphore,Timer等等。下面这篇文章主要通过案例来说明其中的Event和Segmaphore(Boundedsegmaphore)的使用。

Event

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

Event类实例函数

立即学习“Python免费学习笔记(深入)”;

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

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

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

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

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

 具体代码:

from time import ctime,sleepevent = 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 Eventfrom  threading import Threadimport threadingevent = 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,Threadfrom time import sleepfrom random import randrangelock = Lock()num = 6hotel = 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 roomI want to logoutA customer logout...Welcome again还剩5 房间I want to logoutA customer logout...Welcome again还剩6 房间I want to loginA customer login...Ok,your room number is...还剩5 房间I want to loginA customer login...Ok,your room number is...还剩4 房间

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