一:并行,并发概念
- 并发:指系统具有操作多个任务的能力
- 并行:指形同具有同时操作多个任务的能力
- 并行可以看作是并发的子集
二:同步,异步概念
- 同步:所谓同步,就是发出一个功能调用时,在没有得到结果之前,该调用就不返回或不继续执行后续操作-------就是等
- 个人理解:当程序出现阻塞的时候,一直等到阻塞结束
- 异步:当一个异步过程调用发出后,调用者在没有得到结果之前,就可以继续执行后续操作
- 个人理解:当程序处于阻塞的时候,就去执行其他的操作,等到阻塞结束,再回来
一:GIL
- 首先需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念
- 即全局解释器所(global interpreter lock),每个线程在执行时候都需要先获取GIL,保证同一时刻只有一个线程可以执行代码,即同一时刻只有一个线程使用CPU,也就是说多线程并不是真正意义上的同时执行
二:任务分类
- IO密集型任务:python的多线程是有意义的
- 计算密集型任务:不适合python
GIL一篇文章:https://blog.csdn.net/weixin_41594007/article/details/79485847
一:同步锁
通常被用来实现对共享资源的同步访问,为每一个共享资源创建一个Lock对象,当你需要访问该资源时,调用acquire()方法来获取锁对象(如果其他线程已经获得了该锁,则当前线程需要等待其被释放才能拿到该锁),待资源访问完后,在调用release方式释放锁
二:代码实例解析
1 def minus(): 2 lock.acquire()#对资源进行枷锁 3 global num 4 temp=num 5 time.sleep(0.0001) 6 num=temp-1 7 lock.release()#对资源释放锁 8 if __name__=="__main__": 9 import threading, time 10 num=100 11 thread=[] 12 lock = threading.Lock() 13 for i in range(100): 14 i=threading.Thread(target=minus) 15 thread.append(i) 16 i.start() 17 for t in thread:#让主线程等待子线程完毕再执行 18 t.join() 19 print(num)
不加同步锁的解析 1.再没有time.sleep的时候程序结果为0 2.但在加入time.sleep时会发现随时间的不一样,答案也不一样 time.sleep(1):99 3.时间一样,但每次结果也不一样 time.sleep(0.001):88 84 89..... 4.猜想:当遇到sleep时,cpu就会切换线程去执行,当sleep时间刚好切换过100此线程之后,又开始执行这100个线程的最后一步,导致结果为100 当遇到sleep不够切换100次线程时,第一个线程先开始temp=100,遇到sleep切换到第二个线程,第二个线程temp也为100,但当第二次切换线程时,有可能去到第一个线程去执行第二部, 这样就会出现这种情况 以上为个人理解 ----------------------------------------------------------------------------------------------------
三:同步锁理解:对于加锁部分,不会出现子线程的切换,但可以切换到主线程,从而产生的效果是加锁部分多线程是串行执行的
一:死锁
- 在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁,因为系统判断这部分资源都正在使用,所有这两个线程在无外力作用下将一直等待下去
1 import threading 2 import time 3 class MyThread(threading.Thread): 4 def actionA(self): 5 A.acquire() 6 print(self.name,"gotA",time.ctime(),end=' ') 7 time.sleep(2) 8 9 B.acquire() 10 print(self.name,"gotB",time.ctime(),end=' ') 11 time.sleep(1) 12 13 B.release() 14 A.release() 15 def actionB(self): 16 B.acquire() 17 print(self.name,'gotB',time.ctime(),end=' ') 18 time.sleep(2) 19 20 A.acquire() 21 print(self.name,"gotA",time.ctime(),end=' ') 22 time.sleep(1) 23 24 A.release() 25 B.release() 26 27 def run(self):#重写run方法 28 self.actionA() 29 time.sleep(0.5) 30 self.actionB() 31 if __name__=="__main__": 32 #r_lock=threading.RLock()#递归锁 33 A=threading.Lock() 34 B=threading.Lock() 35 thread=[] 36 for t in range(4): 37 t=MyThread() 38 thread.append(t) 39 t.start() 40 41 for i in thread: 42 i.join() 43 44 print("ending......")
第一步:程之间竞争执行权,线程1执行sactionA方法,由于方法中有同步锁,所以其他线程只能等待该线程执行结束,线程1执行完sactionA方法,并且释放了A,B锁,进入等待时间 Thread-1 gotA Sun Feb 10 11:01:54 2019 Thread-1 gotB Sun Feb 10 11:01:56 2019 第二步:线程之间再次争夺执行权,线程2拿到执行权执行sactionA方法,并进入等待时间 Thread-2 gotA Sun Feb 10 11:06:28 2019 第三步:线程1的等待时间完毕,执行sactionB Thread-1 gotB Sun Feb 10 11:06:29 2019 第四步:由于线程1拿到B锁,线程2到A锁,线程1要拿A锁,线程2要拿B锁,所以产生了死锁 #saction之间的sleep是为了观看结果的,但是时间不能太长不然线程2就拿到了A,B锁了
二:递归锁
- 同一个线程可以多次获取同一个锁,不会产生死锁
- r_lock=threading.RLock()
- 递归锁是通过计数器来实现,acquire是计数器+1,release-1,计数器>0时,其他线程不能获得该锁
一:概念
-
事件是一个简单的同步对象;该事件表示一个内部标志,线程可以等待设置标志,或者自己设置或清除标志。、
- event=threading.Event()
二:方法:
- a client thread can wait for the flag to be set
event.wait() - a server thread can set or clear it
event.set()
event.clear() - If the flag is set, the wait method doesn’t do anything.
If the flag is cleared, wait will block until it becomes set again.
Any number of threads may wait for the same event.
三:实例
1 import threading,time 2 class Boss(threading.Thread): 3 def run(self): 4 print("BOSS:今晚大家都要加班到22:00。") 5 print(event.isSet()) 6 event.set() 7 time.sleep(5) 8 print("BOSS:<22:00>可以下班了。") 9 print(event.isSet()) 10 event.set() 11 class Worker(threading.Thread): 12 def run(self): 13 event.wait() 14 print("Worker:哎……命苦啊!") 15 time.sleep(1) 16 event.clear() 17 event.wait() 18 print("Worker:OhYeah!") 19 if __name__=="__main__": 20 event=threading.Event() 21 threads=[] 22 for i in range(5): 23 threads.append(Worker()) 24 threads.append(Boss()) 25 for t in threads: 26 t.start() 27 for t in threads: 28 t.join()
一:信号量(锁)
- 信号量用来控制线程并发数的,BoundedSemaphore或Semaphore管理一个内置的计数 器,每当调用acquire()时-1,调用release()时+1。 计数器不能小于0,当计数器为 0时,acquire()将阻塞线程至同步锁定状态(不能有其他子线程去执行该锁内的资源),直到其他线程调用release()
- semaphore=threading.Semaphore(5)#同时可以有5个线程执行
- semaphore.acquire(),semaphore.release()
1 import threading,time 2 class myThread(threading.Thread): 3 def run(self): 4 if semaphore.acquire(): 5 print(self.name) 6 time.sleep(2) 7 semaphore.release() 8 if __name__=="__main__": 9 semaphore=threading.Semaphore(5) 10 thrs=[] 11 for i in range(20): 12 thrs.append(myThread()) 13 for t in thrs: 14 t.start()