python基础-信号量Semaphore(进程_线程)、事件Event(进程_线程)
2017-12-06 22:38
751 查看
信号量
进程信号量
线程信号量
事件
线程事件
进程事件
输出如下:
Semaphore管理一个内置的计数器,
每当调用acquire()时内置计数器-1;
调用release() 时内置计数器+1;
计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。
输出如下:
event.isSet():返回event的状态值;
event.wait():如果 event.isSet()==False将阻塞线程;
event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
event.clear():恢复event的状态值为False。
我们来看一个例子:
例如,有多个工作线程尝试链接MySQL,我们想要在链接前确保MySQL服务正常才让那些工作线程去连接MySQL服务器,如果连接不成功,都会去尝试重新连接。那么我们就可以采用threading.Event机制来协调各个工作线程的连接操作
输出如下:
上例的代码大概意思是:
开启3个线程,2个是链接操作,1个是监测链接,初始化event.is_set为false,链接线程链接(通过print说明),然后event.wait(1)将阻塞线程1秒,然后另外一个链接线程,同样的操作,同时运行的check线程,在1.5秒后,设置event的状态值为True,在2个链接线程进行第二次链接时候,就输出链接成功了
输出如下:
E:\python\python_sdk\python.exe E:/python/py_pro/python.py
<9328>第1次尝试链接
<6400>第1次尝试链接
[5648]正在检查mysql
<9328>第2次尝试链接
<6400>第2次尝试链接
<9328>链接成功
<6400>链接成功
Process finished with exit code 0
进程信号量
线程信号量
事件
线程事件
进程事件
信号量
进程信号量
互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去,如果指定信号量为3,那么来一个人获得一把锁,计数加1,当计数等于3时,后面的人均需要等待。一旦释放,就有人可以获得一把锁信号量与进程池的概念很像,但是要区分开,信号量涉及到加锁的概念
from multiprocessing import Process,Semaphore import time,random def go_wc(sem,user): sem.acquire() print('%s 占到一个茅坑' %user) time.sleep(random.randint(0,3)) #模拟每个人拉屎速度不一样,0代表有的人蹲下就起来了 sem.release() if __name__ == '__main__': sem=Semaphore(3) p_l=[] for i in range(10): p=Process(target=go_wc,args=(sem,'user%s' %i,)) p.start() p_l.append(p) for i in p_l: i.join() print('============》')
输出如下:
E:\python\python_sdk\python.exe E:/python/py_pro/python.py user0 占到一个茅坑 user1 占到一个茅坑 user2 占到一个茅坑 user3 占到一个茅坑 user4 占到一个茅坑 user5 占到一个茅坑 user6 占到一个茅坑 user7 占到一个茅坑 user8 占到一个茅坑 user9 占到一个茅坑 ============》 Process finished with exit code 0
线程信号量
同进程的一样Semaphore管理一个内置的计数器,
每当调用acquire()时内置计数器-1;
调用release() 时内置计数器+1;
计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。
def func(sm): sm.acquire() print('%s get sm' %threading.current_thread().getName()) time.sleep(2) sm.release() if __name__ == '__main__': sm=Semaphore(3) for i in range(10): t=Thread(target=func,args=(sm,)) t.start()
输出如下:
E:\python\python_sdk\python.exe E:/python/py_pro/python.py Thread-1 get sm Thread-2 get sm Thread-3 get sm Thread-4 get sm Thread-5 get sm Thread-6 get sm Thread-7 get sm Thread-9 get sm Thread-8 get sm Thread-10 get sm Process finished with exit code 0
事件
线程事件
线程的一个关键特性是每个线程都是独立运行且状态不可预测。如果程序中的其 他线程需要通过判断某个线程的状态来确定自己下一步的操作,这时线程同步问题就会变得非常棘手。为了解决这些问题,我们需要使用threading库中的Event对象。 对象包含一个可由线程设置的信号标志,它允许线程等待某些事件的发生。在 初始情况下,Event对象中的信号标志被设置为假。如果有线程等待一个Event对象, 而这个Event对象的标志为假,那么这个线程将会被一直阻塞直至该标志为真。一个线程如果将一个Event对象的信号标志设置为真,它将唤醒所有等待这个Event对象的线程。如果一个线程等待一个已经被设置为真的Event对象,那么它将忽略这个事件, 继续执行event.isSet():返回event的状态值;
event.wait():如果 event.isSet()==False将阻塞线程;
event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
event.clear():恢复event的状态值为False。
我们来看一个例子:
例如,有多个工作线程尝试链接MySQL,我们想要在链接前确保MySQL服务正常才让那些工作线程去连接MySQL服务器,如果连接不成功,都会去尝试重新连接。那么我们就可以采用threading.Event机制来协调各个工作线程的连接操作
from threading import Thread,Event import threading import time,random def conn_mysql(): count=1 #初始状态false while not event.is_set(): if count > 3: raise TimeoutError('链接超时') print('<%s>第%s次尝试链接' % (threading.current_thread().getName(), count)) event.wait(1) count+=1 print('<%s>链接成功' %threading.current_thread().getName()) def check_mysql(): print('\033[45m[%s]正在检查mysql\033[0m' % threading.current_thread().getName()) time.sleep(1.5) #设置event的状态值为True event.set() if __name__ == '__main__': event=Event() conn1=Thread(target=conn_mysql) conn2=Thread(target=conn_mysql) check=Thread(target=check_mysql) conn1.start() conn2.start() check.start()
输出如下:
E:\python\python_sdk\python.exe E:/python/py_pro/python.py <Thread-1>第1次尝试链接 <Thread-2>第1次尝试链接 [Thread-3]正在检查mysql <Thread-1>第2次尝试链接 <Thread-2>第2次尝试链接 <Thread-2>链接成功 <Thread-1>链接成功 Process finished with exit code 0
上例的代码大概意思是:
开启3个线程,2个是链接操作,1个是监测链接,初始化event.is_set为false,链接线程链接(通过print说明),然后event.wait(1)将阻塞线程1秒,然后另外一个链接线程,同样的操作,同时运行的check线程,在1.5秒后,设置event的状态值为True,在2个链接线程进行第二次链接时候,就输出链接成功了
进程事件
# from threading import Thread,Event # import threading import time,random,os from multiprocessing import Process,Event def conn_mysql(event): count=1 #初始状态false while not event.is_set(): if count > 3: raise TimeoutError('链接超时') print('<%s>第%s次尝试链接' % (os.getpid(), count)) event.wait(1) count+=1 print('<%s>链接成功' %os.getpid()) def check_mysql(event): print('\033[45m[%s]正在检查mysql\033[0m' % os.getpid()) time.sleep(1.5) #设置event的状态值为True event.set() if __name__ == '__main__': event=Event() conn1=Process(target=conn_mysql,args=(event,)) conn2=Process(target=conn_mysql,args=(event,)) check=Process(target=check_mysql,args=(event,)) conn1.start() conn2.start() check.start()
输出如下:
E:\python\python_sdk\python.exe E:/python/py_pro/python.py
<9328>第1次尝试链接
<6400>第1次尝试链接
[5648]正在检查mysql
<9328>第2次尝试链接
<6400>第2次尝试链接
<9328>链接成功
<6400>链接成功
Process finished with exit code 0
相关文章推荐
- python中的线程之semaphore信号量
- Python基础 - 第九天 - paramiko模块、进程、线程
- Windows中线程的基础知识和简单应用----信号量(Semaphore)
- Windows 临界区CRITICAL_SECTION,内核事件Event,互斥量Mutex,信号量Semaphore
- Python基础之多线程事件Event
- 临界区(Critical Section)、互斥量(Mutex)、信号量(Semaphore)、事件(Event)的区别
- 多线程基础之三:使用event, mutex, semaphore实现多进程间互斥
- Python基础学习(5)网络编程socket、文件上传、粘包问题、socketserver、IO多路复用、线程与进程、进程池、线程池、上下文管理、协程
- python中的线程之semaphore信号量
- python基础-守护进程、守护线程、守护非守护并行
- python类库32[多进程同步Lock+Semaphore+Event]
- Windows 临界区CRITICAL_SECTION,内核事件Event,互斥量Mutex,信号量Semaphore
- python基础之Event对象、队列和多进程基础
- 关于Python的进程线程协程之threading模块(二)Lock,RLock对象以及Semaphore,BoundedSemaphore对象
- Python基础:进程、线程、协程(1)
- Python基础之九进程和线程
- Python基础—线程、进程和协程
- Python基础-进程和线程
- 进程和线程的基础知识——Python学习笔记11
- python基础-线程和进程