线程有2种调用方式,如下:
直接调用
1 import threading 2 import time 3
4 def sayhi(num): #定义每个线程要运行的函数 6 print("running on number:%s" %num) 8 time.sleep(3) 9 10 if __name__ == '__main__': 12 t1 = threading.Thread(target=sayhi,args=(1,)) #生成一个线程实例 13 t2 = threading.Thread(target=sayhi,args=(2,)) #生成另一个线程实例 15 t1.start() #启动线程 16 t2.start() #启动另一个线程 18 print(t1.getName()) #获取线程名 19 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上的结果总是正确的,可能是自动加了锁
1 import time 2 import threading 3 4 5 def addNum(): 6 global num # 在每个线程中都获取这个全局变量 7 print('--get num: %s' %num) 8 time.sleep(1) 9 lock.acquire() # 修改数据前加锁 10 num -= 1 # 对此公共变量进行-1操作 11 lock.release() # 修改后释放 12 13 num = 100 # 设定一个共享变量 14 thread_list = [] 15 lock = threading.Lock() #生成全局锁 16 for i in range(100): 17 t = threading.Thread(target=addNum) 18 t.start() 19 print "threading num: %s " %threading.active_count() #查看线程数 20 thread_list.append(t) 21 22 for t in thread_list: # 等待所有线程执行完毕 23 t.join() 24 25 print('final num:', num)
死锁
所谓死锁:是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程成为死锁进程。
1 import threading 2 import time 3 4 mutexA = threading.Lock() 5 mutexB = threading.Lock() 6 7 class MyThread(threading.Thread): 8 def __init__(self): 9 threading.Thread.__init__(self) 10 11 def run(self): 12 self.fun1() 13 self.fun2() 14 15 def fun1(self): 16 mutexA.acquire() 17 print("fun1 I am %s,get res:%s---%s" % (self.name, "ResA", time.time())) 18 19 mutexB.acquire()#线程2卡在这里,获取不到锁B,线程2此时已经有锁A 20 print("fun1 I am %s,get res:%s---%s" % (self.name, "ResB", time.time())) 21 mutexB.release() 22 print("FUN1 I am %s, release res:%s---%s" % (self.name, "ResB", time.time())) 23 mutexA.release() 24 print("FUN1 I am %s, release res:%s---%s" % (self.name, "ResA", time.time())) 25 26 def fun2(self): 27 mutexB.acquire() 28 print("fun2 I am %s,get res:%s---%s" % (self.name, "ResB", time.time())) 29 30 time.sleep(0.3) #这里整个进程sleep, 31 print("sleep fun2 I am %s,get res:%s---%s" % (self.name, "ResB", time.time())) 32 33 mutexA.acquire()#线程1卡在这一步,线程1此时已经有锁b 34 print("fun2 I am %s,get res:%s---%s" % (self.name, "ResA", time.time())) 35 36 mutexA.release() 37 print("FUN1 I am %s, release res:%s---%s" % (self.name, "ResA", time.time())) 38 39 mutexB.release() 40 print("FUN1 I am %s, release res:%s---%s" % (self.name, "ResB", time.time())) 41 42 43 if __name__ == '__main__': 44 print("start------------%s", time.time()) 45 for i in range(0, 10): #一次循环,代表一个线程 46 print "%s " %i 47 my_thread = MyThread() 48 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,其他的线程才能获得资源。
1 Rlock = threading.RLock() 2 class MyThread(threading.Thread): 3 def __init__(self): 4 threading.Thread.__init__(self) 5 6 def run(self): 7 self.fun1() 8 self.fun2() 9 10 def fun1(self): 11 Rlock.acquire() # 如果锁被占用,则阻塞在这里,等待锁的释放 12 print("I am %s,get res:%s---%s" % (self.name, "ResA", time.time())) 13 Rlock.acquire() # count=2 14 print("I am %s,get res:%s---%s" % (self.name, "ResB", time.time())) 15 16 Rlock.release() # count-1 17 Rlock.release() # count-1=0 18 19 def fun2(self): 20 Rlock.acquire() # count=1 21 print("I am %s,get res:%s---%s" % (self.name, "ResB", time.time())) 22 time.sleep(0.2) 23 24 Rlock.acquire() # count=2 25 print("I am %s,get res:%s---%s" % (self.name, "ResA", time.time())) 26 Rlock.release() # coun-1 27 Rlock.release() # count-1 28 29 30 if __name__ == '__main__': 31 print("start-----------%s" % time.time()) 32 for i in range(0, 10): 33 my_thread = MyThread() 34 my_thread.start()
Semaphore(信号量)
原理:来限制一个时间点内的线程数量。比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去。
1 def run(n): 2 semaphore.acquire() 3 time.sleep(1) 4 print("run the thread: %s " %n) 5 semaphore.release() 6 7 if __name__ == '__main__': 8 num= 0 9 semaphore = threading.BoundedSemaphore(5) #最多允许5个线程同时运行 10 for i in range(20): 11 t = threading.Thread(target=run,args=(i,)) 12 t.start() 13 14 while threading.active_count() != 1: 15 pass #print threading.active_count() 16 else: 17 print('----all threads done---') 18 print(num)
Events
通过Event来实现两个或多个线程间的交互,下面是一个红绿灯的例子,即起动一个线程做交通指挥灯,生成几个线程做车辆,车辆行驶按红灯停,绿灯行的规则。
红绿灯
1 import threading,time 2 import random 3 def light(): 4 if not event.isSet(): 5 event.set() #wait就不阻塞 #绿灯状态 6 count = 0 7 while True: 8 if count < 10: 9 print('