python theading线程开发与加锁、信号量、事件等详解
线程有2种调用方式,如下:
直接调用
import threading
import time
def sayhi(num): #定义每个线程要运行的函数
print("running on number:%s" %num)
time.sleep(3) if __name__ == '__main__':
t1 = threading.Thread(target=sayhi,args=(1,)) #生成一个线程实例
t2 = threading.Thread(target=sayhi,args=(2,)) #生成另一个线程实例
t1.start() #启动线程
t2.start() #启动另一个线程
print(t1.getName()) #获取线程名
print(t2.getName())
继承式调用
import threading
import time
class MyThread(threading.Thread):
def __init__(self,num):
threading.Thread.__init__(self)
self.num = num def run(self):#定义每个线程要运行的函数
print("running on number:%s" %self.num)
time.sleep(3) if __name__ == '__main__':
t1 = MyThread(1)
t2 = MyThread(2)
t1.start()
t2.start()
同步锁(py2版本) *注:不要在3.x上运行,不知为什么,3.x上的结果总是正确的,可能是自动加了锁
import time
import threading def addNum():
global num # 在每个线程中都获取这个全局变量
print('--get num: %s' %num)
time.sleep(1)
lock.acquire() # 修改数据前加锁
num -= 1 # 对此公共变量进行-1操作
lock.release() # 修改后释放 num = 100 # 设定一个共享变量
thread_list = []
lock = threading.Lock() #生成全局锁
for i in range(100):
t = threading.Thread(target=addNum)
t.start()
print "threading num: %s \n" %threading.active_count() #查看线程数
thread_list.append(t) for t in thread_list: # 等待所有线程执行完毕
t.join() print('final num:', num)
死锁
所谓死锁:是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程成为死锁进程。
import threading
import time mutexA = threading.Lock()
mutexB = threading.Lock() class MyThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self) def run(self):
self.fun1()
self.fun2() def fun1(self):
mutexA.acquire()
print("fun1 I am %s,get res:%s---%s" % (self.name, "ResA", time.time())) mutexB.acquire()#线程2卡在这里,获取不到锁B,线程2此时已经有锁A
print("fun1 I am %s,get res:%s---%s" % (self.name, "ResB", time.time()))
mutexB.release()
print("FUN1 I am %s, release res:%s---%s" % (self.name, "ResB", time.time()))
mutexA.release()
print("FUN1 I am %s, release res:%s---%s" % (self.name, "ResA", time.time())) def fun2(self):
mutexB.acquire()
print("fun2 I am %s,get res:%s---%s" % (self.name, "ResB", time.time())) time.sleep(0.3) #这里整个进程sleep,
print("sleep fun2 I am %s,get res:%s---%s" % (self.name, "ResB", time.time())) mutexA.acquire()#线程1卡在这一步,线程1此时已经有锁b
print("fun2 I am %s,get res:%s---%s" % (self.name, "ResA", time.time())) mutexA.release()
print("FUN1 I am %s, release res:%s---%s" % (self.name, "ResA", time.time())) mutexB.release()
print("FUN1 I am %s, release res:%s---%s" % (self.name, "ResB", time.time())) if __name__ == '__main__':
print("start------------%s", time.time())
for i in range(0, 10): #一次循环,代表一个线程
print "%s \n" %i
my_thread = MyThread()
my_thread.start()
运行结果
0
fun1 I am Thread-1,get res:ResA---1551263063.35 #线程1获得锁B
fun1 I am Thread-1,get res:ResB---1551263063.35 #线程1获得锁B
FUN1 I am Thread-1, release res:ResB---1551263063.35 #线程1释放锁B
FUN1 I am Thread-1, release res:ResA---1551263063.35 #线程1释放锁A
fun2 I am Thread-1,get res:ResB---1551263063.35 #线程1获得锁B
1
fun1 I am Thread-2,get res:ResA---1551263063.35 #线程2释放锁A
2
..
9
sleep fun2 I am Thread-1,get res:ResB---1551263065.35 #线程2释放锁B
总结:
1、线程1已有B锁,准备获取A锁
2、线程2已有A锁,准备获取B锁
1和2同一时刻,因此互相等待
RLock(递归锁)
说白了就是在一个大锁中还要再包含子锁
在python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。
Rlock = threading.RLock()
class MyThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self) def run(self):
self.fun1()
self.fun2() def fun1(self):
Rlock.acquire() # 如果锁被占用,则阻塞在这里,等待锁的释放
print("I am %s,get res:%s---%s" % (self.name, "ResA", time.time()))
Rlock.acquire() # count=2
print("I am %s,get res:%s---%s" % (self.name, "ResB", time.time())) Rlock.release() # count-1
Rlock.release() # count-1=0 def fun2(self):
Rlock.acquire() # count=1
print("I am %s,get res:%s---%s" % (self.name, "ResB", time.time()))
time.sleep(0.2) Rlock.acquire() # count=2
print("I am %s,get res:%s---%s" % (self.name, "ResA", time.time()))
Rlock.release() # coun-1
Rlock.release() # count-1 if __name__ == '__main__':
print("start-----------%s" % time.time())
for i in range(0, 10):
my_thread = MyThread()
my_thread.start()
Semaphore(信号量)
原理:来限制一个时间点内的线程数量。比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去。
def run(n):
semaphore.acquire()
time.sleep(1)
print("run the thread: %s\n" %n)
semaphore.release() if __name__ == '__main__':
num= 0
semaphore = threading.BoundedSemaphore(5) #最多允许5个线程同时运行
for i in range(20):
t = threading.Thread(target=run,args=(i,))
t.start() while threading.active_count() != 1:
pass #print threading.active_count()
else:
print('----all threads done---')
print(num)
Events
通过Event来实现两个或多个线程间的交互,下面是一个红绿灯的例子,即起动一个线程做交通指挥灯,生成几个线程做车辆,车辆行驶按红灯停,绿灯行的规则。
红绿灯
import threading,time
import random
def light():
if not event.isSet():
event.set() #wait就不阻塞 #绿灯状态
count = 0
while True:
if count < 10:
print('\033[42;1m--green light on---\033[0m')
elif count <13:
print('\033[43;1m--yellow light on---\033[0m')
elif count <20:
if event.isSet():
event.clear()
print('\033[41;1m--red light on---\033[0m')
else:
count = 0
event.set() #打开绿灯
time.sleep(1)
count +=1
def car(n):
while 1:
time.sleep(random.randrange(10))
if event.isSet(): #绿灯
print("car [%s] is running.." % n)
else:
print("car [%s] is waiting for the red light.." %n)
if __name__ == '__main__':
event = threading.Event()
Light = threading.Thread(target=light)
Light.start()
for i in range(3):
t = threading.Thread(target=car,args=(i,))
t.start()
员工过门禁
import threading
import time
import random def door():
door_open_time_counter = 0
while True:
if door_swiping_event.is_set():
print("\033[32;1mdoor opening....\033[0m")
door_open_time_counter +=1
else:
print("\033[31;1mdoor closed....,please swipe to open.\033[0m")
door_open_time_counter = 0 #清空计时器
door_swiping_event.wait()
if door_open_time_counter > 3:#门开了已经3s了,该关了
door_swiping_event.clear()
time.sleep(0.5) def staff(n):
print("staff [%s] is comming..." % n )
while True:
if door_swiping_event.is_set():
print("\033[34;1mdoor is opened, staff [%s] passing.....over!!\033[0m" % n )
break
else:
print("STAFF [%s] sees door got closed, swipping the card....." % n)
door_swiping_event.set()
print("after set,,, staff [%s]--------" %n,door_swiping_event.is_set())
# time.sleep(0.5) door_swiping_event = threading.Event() #设置事件
door_thread = threading.Thread(target=door)
door_thread.start()
for i in range(5):
p = threading.Thread(target=staff,args=(i,))
time.sleep(random.randrange(3))
p.start()
运行结果
door closed....,please swipe to open.
staff [0] is comming...
STAFF [0] sees door got closed, swipping the card.....
('after set,,, staff [0]--------', True)
door is opened, staff [0] passing.....over!!
door opening....
door opening....
door opening....
door opening....
staff [1] is comming...
STAFF [1] sees door got closed, swipping the card.....
('after set,,, staff [1]--------'staff [2] is comming...,
Truedoor is opened, staff [2] passing.....over!!) door is opened, staff [1] passing.....over!!
door opening....
door closed....,please swipe to open.
staff [3] is comming...
STAFF [3] sees door got closed, swipping the card.....
('after set,,, staff [3]--------', True)
door is opened, staff [3] passing.....over!!
door opening....
door opening....
staff [4] is comming...
door is opened, staff [4] passing.....over!!
door opening....
door opening....
door closed....,please swipe to open.
python theading线程开发与加锁、信号量、事件等详解的更多相关文章
- [ 转载 ] Java开发中的23种设计模式详解(转)
Java开发中的23种设计模式详解(转) 设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类 ...
- python中日志logging模块的性能及多进程详解
python中日志logging模块的性能及多进程详解 使用Python来写后台任务时,时常需要使用输出日志来记录程序运行的状态,并在发生错误时将错误的详细信息保存下来,以别调试和分析.Python的 ...
- Java线程通讯方法之wait()、nofity() 详解
Java线程通讯方法之wait().nofity() 详解 本文将探讨以下问题: synchronized 代码块使用 notify()与notifyAll()的区别 Java wait(),noti ...
- jQuery 事件用法详解
jQuery 事件用法详解 目录 简介 实现原理 事件操作 绑定事件 解除事件 触发事件 事件委托 事件操作进阶 阻止默认事件 阻止事件传播 阻止事件向后执行 命名空间 自定义事件 事件队列 jque ...
- cocos2dx+lua注册事件函数详解
coocs2dx 版本 3.1.1 registerScriptTouchHandler 注册触屏事件 registerScriptTapHandler 注册点击事件 registerScriptHa ...
- 最锋利的Visual Studio Web开发工具扩展:Web Essentials详解
原文:最锋利的Visual Studio Web开发工具扩展:Web Essentials详解 Web Essentials是目前为止见过的最好用的VS扩展工具了,具体功能请待我一一道来. 首先,从E ...
- cocos2dx+lua注册事件函数详解 事件
coocs2dx 版本 3.1.1 registerScriptTouchHandler 注册触屏事件 registerScriptTapHandler ...
- (转载)【cocos2dx 3.x Lua] 注册事件函数详解
出处: http://www.2cto.com/kf/201409/338235.html coocs2dx 版本 3.1.1 registerScriptTouchHandler 注册触屏事件 re ...
- 委托与事件代码详解与(Object sender,EventArgs e)详解
委托与事件代码详解 using System;using System.Collections.Generic;using System.Text; namespace @Delegate //自定义 ...
随机推荐
- template render in javascript
art-template for github 中文官方文档
- error: pcap library not found! 解决方法
参考: error: pcap library not found! error: pcap library not found! 解决方法 $ sudo apt-get install libsql ...
- 每天一个小程序—0013题(爬图片+正则表达式 or BeautifulSoup)
第 0013 题: 用 Python 写一个爬图片的程序,爬 这个链接里的日本妹子图片 :-) 关于python3的urllib模块,可以看这篇博客:传送门 首先是用urlopen打开网站并且获取网页 ...
- 搭建 FTP 文件服务
1.安装并启动 FTP 服务 2.配置 FTP 权限 3.准备域名和证书 4.访问 FTP 安装 VSFTPD 使用 yum 安装 vsftpd: yum install vsftpd -y vsft ...
- Tomcat的manager app管理web项目
1.在浏览器地址栏输入http://localhost:8080/进入,如下图所示: 2.在点击Manager App 前,首次使用则需要对tomcat目录下的conf/tomcat-users.xm ...
- Android 4.0之后的日历控件拥挤的解决办法
本意是想做成这个样子的控件: 发现使用datepicker之后,效果完全不同,把整个日历都显示出来了.非常拥挤. 在datepicker中加入android:calendarViewShown=&qu ...
- echo -n 和echo -e 参数意义
echo -n 不换行输出 $echo -n "123" $echo "456" 1 2 最终输出 123456 而不是 123 456 1 2 3 4 5 6 ...
- 【Java】【绘图】
绘图原理(1)Component类提供了两个和绘图相关最重要的⽅法:1. paint(Graphics g)绘制组件的外观2. repaint()刷新组件的外观当组件第⼀次在屏幕显示的时候,程序会⾃动 ...
- _event_active_team
EventId 事件ID GUID 对应creature或gameobject表中 guid,正数为生物,负数为物体 TeamId 事件玩家分组,攻守(防守为1,进攻为2),自定义阵营(_factio ...
- idea使用教程(2)
目录: 1. open和import的区别 2.修改虚拟机配置信息 3.安装目录和设置目录 1. open和import的区别 open:如果本身就是idea项目,则可以直接open打开; impor ...