有关多线程(同步锁,递归锁,同步对象,信号量)

上面一个随笔已经简单介绍了多线程,比如下面在举个简单的例子:

 1 #!/usr/bin/env python
 2 #-*-coding:utf-8 -*-
 3
 4 import threading
 5 import time
 6
 7 def add():
 8     sum = 0
 9
10     for i in range(1000000):
11         sum += i
12
13     print("sum: ",sum)
14
15
16 def mul():
17     sum2 = 1
18     for i in range(1,100000):
19         sum2 *= i
20
21     print("sum2: ",sum2)
22
23
24 if __name__ == ‘__main__‘:
25
26     start = time.time()
27     t1 = threading.Thread(target=add)
28     t2 = threading.Thread(target=mul)
29
30     l = []
31     l.append(t1)
32     l.append(t2)
33
34     for t in l:
35         t.start()
36
37     for t in l:
38         t.join()
39
40     print("cost time %s"%(time.time()-start))

但是当多线程处理共享数据等问题时,简单的多线程会遇到一些困难,比如:

 1 import threading
 2 import time
 3
 4 def sub():
 5
 6     global num
 7
 8     # num -= 1
 9     temp = num          # 一下三行与上一行意思一样,只是加了一个时间
10     time.sleep(0.0001)
11     num = temp-1
12 ‘‘‘
13 这样结果就不像原来的0了,原因是,原来线程1过来减1后,num少一,没问题;
14 现在加了.sleep(),当线程1到temp = num 时,因为到等待,所以切换给下一个线程,线程2拿到的还是100,
15 等第一线程到num = temp -1 = 99 时,下一个线程的temp还是100。
16 一个线程cpu还没处理结束,交出处理权,但是它们共享一个数据,所以可能出错。
17 解决办法,执行上面三行的过程中,CPU不可以切换,就OK了,因此同步锁诞生。详细见lesson3
18 ‘‘‘
19
20 num = 100
21
22 l = []
23
24 for i in range(100):         # 开了一百个线程
25     t = threading.Thread(target=sub)
26     t.start()
27     l.append(t)
28
29 for j in l:
30     j.join()

因此对于这种情况需要用同步锁,lock = threading.Lock() 定义锁, lock.acquire()上锁,lock.release()开锁。锁之间内容等于变成串行。使用如下:

 1 import threading
 2 import time
 3
 4 def sub():
 5
 6     global num
 7
 8     # num -= 1
 9     lock.acquire()      # 加上同步锁,意思是,在释放锁前的内容不可以进行CPU线程切换
10
11     temp = num          # 一下三行与上一行意思一样,只是加了一个时间
12     time.sleep(0.001)
13     num = temp-1
14
15     lock.release()
16
17 num = 100
18
19 l = []
20 lock = threading.Lock()
21
22 for i in range(100):         # 开了一百个线程
23     t = threading.Thread(target=sub)
24     t.start()
25     l.append(t)
26
27 for j in l:
28     j.join()
29
30 print(num)

threading.lock

以上说明了为什么需要同步锁,以及它的使用方法,但是在多线程中还有死锁的问题。死锁:在线程见共享拿多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方资源就会造成死锁。比如:下面例子,线程1拿actionB中的B锁后,sleep()时间切换线程,线程2拿了actionA中A锁后,在拿B锁时,发现没有B锁(还在线程1手里),造成死锁。

 1 import  threading,time
 2
 3
 4 # 用继承类创建多线程
 5
 6 class MyThread(threading.Thread):
 7
 8     def actionA(self):
 9         A.acquire()
10         print(self.name,"gotA",time.ctime())       # self.name是线程名
11         time.sleep(2)
12         # 注意A锁还没释放,又上了一把锁
13         B.acquire()
14         print(self.name,"gotB",time.ctime())
15         time.sleep(1)
16
17         B.release()
18         A.release()
19
20     def actionB(self):
21         B.acquire()
22         print(self.name, "gotB", time.ctime())
23         time.sleep(2)
24         # 注意A锁还没释放,又上了一把锁
25         A.acquire()
26         print(self.name, "gotB", time.ctime())
27         time.sleep(1)
28
29         A.release()
30         B.release()
31
32     def run(self):      # run函数名字必须这样,就跟之前handle一个意思
33         self.actionA()
34         time.sleep(2)
35         self.actionB()
36
37
38 if __name__ == ‘__main__‘:
39
40     # 定义两把锁,注意是两把,不是两种,只要两个,你用A的同时,它就不可以
41     A = threading.Lock()
42     B = threading.Lock()
43
44     L = []
45
46     for i in range(5):     # 开了五个线程
47         t = MyThread()
48         t.start()
49         L.append(t)
50
51     for t in L:
52         t.join()

使用递归锁可以解决问题,threading.Rlock(),内部就是多一个计数,acquire一次,内部计数加一个1,release减1,只有计数等于0时,其他线程才可以拿这把锁,不然等待。自己线程可以多次用这个锁。具体如下:

 1 import  threading,time
 2
 3
 4 # 用继承类创建多线程
 5
 6 class MyThread(threading.Thread):
 7
 8     def actionA(self):
 9         r_lock.acquire()
10         print(self.name,"gotA",time.ctime())       # self.name是线程名
11         time.sleep(2)
12         # 注意A锁还没释放,又上了一把锁
13         r_lock.acquire()
14         print(self.name,"gotB",time.ctime())
15         time.sleep(1)
16
17         r_lock.release()
18         r_lock.release()
19
20     def actionB(self):
21         r_lock.acquire()
22         print(self.name, "gotB", time.ctime())
23         time.sleep(2)
24         # 注意A锁还没释放,又上了一把锁
25         r_lock.acquire()
26         print(self.name, "gotB", time.ctime())
27         time.sleep(1)
28
29         r_lock.release()
30         r_lock.release()
31
32     def run(self):      # run函数名字必须这样,就跟之前handle一个意思
33         self.actionA()
34         self.actionB()
35
36
37 if __name__ == ‘__main__‘:
38
39     # 定义两把锁,注意是两把,不是两种,只要两个,你用A的同时,它就不可以
40     # A = threading.Lock()
41     # B = threading.Lock()
42
43     r_lock = threading.RLock()
44
45     L = []
46
47     for i in range(5):     # 开了五个线程
48         t = MyThread()
49         t.start()
50         L.append(t)
51
52     for t in L:
53         t.join()
54
55     print("ending.........")

threading.Rlock

有了同步锁(threading.Lock),递归锁(threading.Rlock),下面介绍threading.Event。说这个之前,先说一下同步对象的概念:当你同时开五个线程执行任务的时候,到底哪个任务先执行,是由抢占CPU决定的,不可控。但是有时候需求需要其中一个特定的线程任务完成到一定阶段,其他线程才可以开始。这时候就涉及到同步对象的概念。

创建同步对象:event = threading.Event()
                         event.set() 设定
                         event.wait() 如果之前没设定,到这步就阻塞等待;如果已经设定,这步等于pass(跳过)
                         event.clear() 清除设定

 1 import threading,time
 2 class Boss(threading.Thread):
 3
 4     def run(self):
 5         print("BOSS:今晚大家都要加班到22:00。")
 6         print(event.isSet())# False
 7         event.set()
 8         time.sleep(5)
 9         print("BOSS:<22:00>可以下班了。")
10         print(event.isSet())
11         event.set()
12
13 class Worker(threading.Thread):
14     def run(self):
15
16         event.wait()#    一旦event被设定,等同于pass
17
18         print("Worker:哎……命苦啊!")
19         time.sleep(1)
20         event.clear()
21         event.wait()
22         print("Worker:OhYeah!")
23
24
25 if __name__=="__main__":
26     event=threading.Event()
27
28
29     threads=[]
30     for i in range(5):
31         threads.append(Worker())
32     threads.append(Boss())
33     for t in threads:         # 本来这6个线程随先执行是随意的(如果没有Event),但是需求肯定是先是老板说加班,员工叫苦,老板说下班,员工欢呼
34         t.start()
35     for t in threads:
36         t.join()
37
38     print("ending.....")

threading.Event

实际应用中可能还有一个信号量的事,也就是允许同时运行的最大线程数目。

 1 import threading,time
 2
 3
 4 class myThread(threading.Thread):
 5     def run(self):
 6
 7         if semaphore.acquire():
 8             print(self.name)
 9             time.sleep(3)
10             semaphore.release()
11
12 if __name__=="__main__":
13     semaphore=threading.Semaphore(5)
14     # semaphore也是一把锁,里面数字代表对于一个加锁任务允许执行的最大线程数
15     thrs=[]
16     for i in range(100):
17         thrs.append(myThread())
18     for t in thrs:
19         t.start()

threading.semaphore

原文地址:https://www.cnblogs.com/maxiaonong/p/9538398.html

时间: 2024-10-08 10:34:31

有关多线程(同步锁,递归锁,同步对象,信号量)的相关文章

python--同步锁/递归锁/协程

同步锁/递归锁/协程 1 同步锁 锁通常被用来实现对共享资源的同步访问,为每一个共享资源创建一个Lock对象,当你需需要访问该资源时,调用acquire()方法来获取锁对象(如果其他线程已经获得了该锁,则当前线程需要等待其被释放),待资源访问完后,在调用release方式释放锁: import threading import time def subnum(): global num # num-=1 lock.acquire() #对用户进行加锁处理 #加锁只对用户数据 等第一个释放完之后才

同步锁 死锁 递归锁

多线程 同步锁(互斥锁) 解决什么问题? 同步锁解决什么问题? 多个线程操作同一个数据,可能会发生数据错乱的问题,因为一个线程拿到数据后,还没来得及对数据进行操作,cpu就有可能去执行另外一个线程,另外一个线程拿到的则是之前线程没有处理完的数据,如下 import threading import time count=20 def zx(): global count print(count) time.sleep(0.001) count-=1 t_list=[] for t in rang

python 并发编程 多线程 死锁现象与递归锁

一 死锁现象 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁 from threading import Thread from threading import Lock import time # 实例化两把不同的锁 mutexA = Lock() mutexB = Lock() class MyThread(Threa

python学习第37天GIL锁、死锁现象与递归锁、信号量、Event时间、线程queue

一.GIL锁 1. 什么是GIL全局解释器锁 定义: In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython's memory management is not thread-safe

11.python并发入门(part4 死锁与递归锁)

一.关于死锁. 死锁,就是当多个进程或者线程在执行的过程中,因争夺共享资源而造成的一种互相等待的现象,一旦产生了死锁,不加人工处理,程序会一直等待下去,这也被称为死锁进程. 下面是一个产生"死锁"现象的例子: import threading import time lock_a = threading.Lock() lock_b = threading.Lock() class test_thread(threading.Thread): def __init__(self): su

10 并发编程-(线程)-GIL全局解释器锁&amp;死锁与递归锁

一.GIL全局解释器锁 1.引子 在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势 首先需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念. 就好比C++是一套语言(语法)标准,但是可以用不同的编译器来编译成可执行代码.>有名的编译器例如GCC,INTEL C++,Visual C++等.Python也一样,同样一段代码可以通过CPython,PyPy,Psyco等不同的Python执行

Python并发编程05/ 死锁/递归锁/信号量/GIL锁/进程池/线程池

目录 Python并发编程05/ 死锁/递归锁/信号量/GIL锁/进程池/线程池 1.昨日回顾 2.死锁现象与递归锁 2.1死锁现象 2.2递归锁 3.信号量 4.GIL全局解释器锁 4.1背景 4.2为什么加锁 5.GIL与Lock锁的区别 6.验证计算密集型IO密集型的效率 6.1 IO密集型 6.2 计算密集型 7.多线程实现socket通信 7.1服务端 7.2客户端 8.进程池,线程池 Python并发编程05/ 死锁/递归锁/信号量/GIL锁/进程池/线程池 1.昨日回顾 #生产者消

并发编程---死锁||递归锁---信号量---Event事件---定时器

死锁 互斥锁:Lock(),互斥锁只能acquire一次 递归锁:  RLock(),可以连续acquire多次,每acquire一次计数器+1,只有计数为0时,才能被抢到acquire # 死锁 from threading import Thread,Lock import time mutexA = Lock() mutexB = Lock() class MyThread(Thread): def run(self): self.f1() self.f2() def f1(self):

线程_递归锁

#死锁:锁只能抢一次,释放后被其他人抢 from threading import Thread,Lock,current_thread import time class MyThread(Thread): def run(self): self.f1() self.f2() def f1(self): mutexA.acquire() print("%s 抢到A锁" %current_thread().getName()) mutexB.acquire() print("