线程有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线程开发与加锁、信号量、事件等详解的更多相关文章

  1. [ 转载 ] Java开发中的23种设计模式详解(转)

    Java开发中的23种设计模式详解(转)   设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类 ...

  2. python中日志logging模块的性能及多进程详解

    python中日志logging模块的性能及多进程详解 使用Python来写后台任务时,时常需要使用输出日志来记录程序运行的状态,并在发生错误时将错误的详细信息保存下来,以别调试和分析.Python的 ...

  3. Java线程通讯方法之wait()、nofity() 详解

    Java线程通讯方法之wait().nofity() 详解 本文将探讨以下问题: synchronized 代码块使用 notify()与notifyAll()的区别 Java wait(),noti ...

  4. jQuery 事件用法详解

    jQuery 事件用法详解 目录 简介 实现原理 事件操作 绑定事件 解除事件 触发事件 事件委托 事件操作进阶 阻止默认事件 阻止事件传播 阻止事件向后执行 命名空间 自定义事件 事件队列 jque ...

  5. cocos2dx+lua注册事件函数详解

    coocs2dx 版本 3.1.1 registerScriptTouchHandler 注册触屏事件 registerScriptTapHandler 注册点击事件 registerScriptHa ...

  6. 最锋利的Visual Studio Web开发工具扩展:Web Essentials详解

    原文:最锋利的Visual Studio Web开发工具扩展:Web Essentials详解 Web Essentials是目前为止见过的最好用的VS扩展工具了,具体功能请待我一一道来. 首先,从E ...

  7. cocos2dx+lua注册事件函数详解 事件

    coocs2dx 版本 3.1.1 registerScriptTouchHandler             注册触屏事件 registerScriptTapHandler             ...

  8. (转载)【cocos2dx 3.x Lua] 注册事件函数详解

    出处: http://www.2cto.com/kf/201409/338235.html coocs2dx 版本 3.1.1 registerScriptTouchHandler 注册触屏事件 re ...

  9. 委托与事件代码详解与(Object sender,EventArgs e)详解

    委托与事件代码详解 using System;using System.Collections.Generic;using System.Text; namespace @Delegate //自定义 ...

随机推荐

  1. dh

    -.-- -.. --- -. --- - -.- -. --- .--

  2. nohup 让进程在后台可靠运行的几种方法

    1. nohup nohup 无疑是我们首先想到的办法.顾名思义,nohup 的用途就是让提交的命令忽略 hangup 信号. nohup 的使用是十分方便的,只需在要处理的命令前加上 nohup 即 ...

  3. P2120 [ZJOI2007]仓库建设(dp+斜率优化)

    思路 首先暴力DP显然,可以得20分 加上一个前缀和优化,可以得到40分 然后上斜率优化 设\(sum_i\)为\(\sum_{1}^iP_i\),\(sump_i\)为\(\sum_{1}^{i}P ...

  4. 用.native修饰器来对外部组件进行构造器内部方法的调用以及用原生js获取构造器里的方法

    html <div id="app"> <span v-text="number"></span> <btn @cli ...

  5. 【Hadoop 分布式部署 四:配置Hadoop 2.x 中主节点(NN和RM)到从节点的SSH无密码登录】

    *******************                一定要使这三台机器的用户名相同,安装目录相同          ************* SSH 无密钥登录的简单介绍(之前再搭 ...

  6. TortoiseGit自动记住用户名密码的方法

    TortoiseGit自动记住用户名密码的方法 windows下比较比较好用的git客户端有2种: msysgit + TortoiseGit(乌龟git) GitHub for Windows gi ...

  7. js判断数字、整数、字符串、布尔,特殊方法

    整数: function isInteger(obj) { return Math.floor(obj) === obj } isInteger(3) // true isInteger(3.3) / ...

  8. EFI环境下的Ubuntu&Win10双系统安装

    因为是win10是EFI启动的,所以网上的easyBCD方法就不可以用了,这里用到的不是ultraiso软碟通,用的哪个忘了 不过只要能写入U盘做成启动盘就ok 具体参考的是https://blog. ...

  9. BSEG和BSIS、BSAS、BSID、BSAD、BSIK、BSAK 六个表的关系

    BSEG和BSIS.BSAS.BSID.BSAD.BSIK.BSAK六个表的关系 1.数据关系: BSAS+BSIS+BSAK+BSIK+BSAD+BSID = BSEG 2.六个表说明: clear ...

  10. HDU 5726 GCD(RMQ+二分)

    http://acm.split.hdu.edu.cn/showproblem.php?pid=5726 题意:给出一串数字,现在有多次询问,每次询问输出(l,r)范围内所有数的gcd值,并且输出有多 ...