线程锁

1.同步锁

1.1多线程抢占资源

 from threading import Thread
 import os,time
 def work():
     global n
     temp=n
     time.sleep(0.1)
     n=temp-1
 if __name__ == '__main__':
     n=100
     l=[]
     for i in range(100):
         p=Thread(target=work)
         l.append(p)
         p.start()
     for p in l:
         p.join()
 
     print(n)

由原来的并发执行变成串行,牺牲了执行效率保证了数据安全

1.2互斥锁和join的区别

 #不加锁:并发执行,速度快,数据不安全
 from threading import current_thread,Thread,Lock
 import os,time
 def task():
     global n
     print('%s is running' %current_thread().getName())
     temp=n
     time.sleep(0.5)
     n=temp-1
 
 
 if __name__ == '__main__':
     n=100
     lock=Lock()
     threads=[]
     start_time=time.time()
     for i in range(100):
         t=Thread(target=task)
         threads.append(t)
         t.start()
     for t in threads:
         t.join()
 
     stop_time=time.time()
     print('主:%s n:%s' %(stop_time-start_time,n))
 
 '''
 Thread-1 is running
 Thread-2 is running
 ......
 Thread-100 is running
 主:0.5216062068939209 n:99
 '''
 
 
 #不加锁:未加锁部分并发执行,加锁部分串行执行,速度慢,数据安全
 from threading import current_thread,Thread,Lock
 import os,time
 def task():
     #未加锁的代码并发运行
     time.sleep(3)
     print('%s start to run' %current_thread().getName())
     global n
     #加锁的代码串行运行
     lock.acquire()
     temp=n
     time.sleep(0.5)
     n=temp-1
     lock.release()
 
 if __name__ == '__main__':
     n=100
     lock=Lock()
     threads=[]
     start_time=time.time()
     for i in range(100):
         t=Thread(target=task)
         threads.append(t)
         t.start()
     for t in threads:
         t.join()
     stop_time=time.time()
     print('主:%s n:%s' %(stop_time-start_time,n))
 
 '''
 Thread-1 is running
 Thread-2 is running
 ......
 Thread-100 is running
 主:53.294203758239746 n:0
 '''
 
 # 有的同学可能有疑问:既然加锁会让运行变成串行,那么我在start之后立即使用join,就不用加锁了啊,也是串行的效果啊
 
 # 没错:在start之后立刻使用jion,肯定会将100个任务的执行变成串行,毫无疑问,最终n的结果也肯定是0,是安全的,但问题是
 
 # start后立即join:任务内的所有代码都是串行执行的,而加锁,只是加锁的部分即修改共享数据的部分是串行的
 
 # 单从保证数据安全方面,二者都可以实现,但很明显是加锁的效率更高.
 from threading import current_thread,Thread,Lock
 import os,time
 def task():
     time.sleep(3)
     print('%s start to run' %current_thread().getName())
     global n
     temp=n
     time.sleep(0.5)
     n=temp-1
 
 
 if __name__ == '__main__':
     n=100
     lock=Lock()
     start_time=time.time()
     for i in range(100):
         t=Thread(target=task)
         t.start()
         t.join()
     stop_time=time.time()
     print('主:%s n:%s' %(stop_time-start_time,n))

死锁和递归锁

进程也有死锁与递归锁

所谓死锁:是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

2.1死锁

 from threading import Lock as Lock
 import time
 mutexA=Lock()
 mutexA.acquire()
 mutexA.acquire()
 print(123)
 mutexA.release()
 mutexA.release()

解决方法:递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。

2.2递归锁

 from threading import RLock as Lock
 import time
 mutexA=Lock()
 mutexA.acquire()
 mutexA.acquire()
 print(123)
 mutexA.release()
 mutexA.release()

信号量

对于信号量我们可以想象成一个容器内的最大容量值,不如说一个房子可以同时容纳5个人,但是有15个人在等着进,这样就可以给这个房子加五把锁,只有拿着锁的钥匙的人才能进,但是当这个人出来的时候必须把要是归还给房子,然后给后边排队的人。

 from threading import Thread,currentThread,Semaphore
 import time
 
 def task():
     sm.acquire()
     print(f'{currentThread().name} 在执行')
     time.sleep(3)
     sm.release()
 
 sm = Semaphore(5)
 for i in range(15):
     t = Thread(target=task)
     t.start()

GIL锁

在Cpython解释器中有一把GIL锁(全局解释器锁),GIl锁本质是一把互斥锁。

导致了同一个进程下,同一时间只能运行一个线程,无法利用多核优势.

同一个进程下多个线程只能实现并发不能实现并行.

为什么要有GIL?

因为cpython自带的垃圾回收机制不是线程安全的,所以要有GIL锁.

导致了同一个进程下,同一时间只能运行一个线程,无法利用多核优势.

分析:

我们有四个任务需要处理,处理方式肯定是要玩出并发的效果,解决方案可以是:

方案一:开启四个进程

方案二:一个进程下,开启四个线程

计算密集型 推荐使用多进程

每个都要计算10s

多线程

在同一时刻只有一个线程会被执行,也就意味着每个10s都不能省,分开每个都要计算10s,共40.ns

多进程

可以并行的执行多个线程,10s+开启进程的时间

io密集型

推荐多线程4个任务每个任务90%大部分时间都在io.

每个任务io10s 0.5s

多线程

可以实现并发,每个线程io的时间不咋占用cpu, 10s + 4个任务的计算时间

多进程

可以实现并行,10s+1个任务执行的时间+开进程的时间

 from threading import Thread
 from multiprocessing import Process
 import time
 
 # 计算密集型
 def work1():
     res=0
     for i in range(100000000): #1+8个0
         res*=i
 
 if __name__ == '__main__':
     t_list = []
     start = time.time()
     for i in range(4):
         # t = Thread(target=work1)
         t = Process(target=work1)
         t_list.append(t)
         t.start()
     for t in t_list:
         t.join()
     end = time.time()
     # print('多线程',end-start) # 多线程 15.413789510726929
     print('多进程',end-start) # 多进程 4.711405515670776
 
 
 # io密集型
 def work1():
     x = 1+1
     time.sleep(5)
 
 
 if __name__ == '__main__':
     t_list = []
     start = time.time()
     for i in range(4):
         t = Thread(target=work1)
         # t = Process(target=work1)
         t_list.append(t)
         t.start()
     for t in t_list:
         t.join()
     end = time.time()
     print('多线程',end-start) # 多线程 5.002625942230225
     # print('多进程',end-start) # 多进程 5.660863399505615
 

 

 

posted on 2019-09-19 14:38  luelue  阅读(135)  评论(0)    收藏  举报