Gil全局解释器锁
GIL是一个互斥锁(存在于Cpython),保证数据的安全(以牺牲效率换区数据的安全性)
阻止同一个进程内多个线程同时执行(不能并行但是能够实现并发)
并发:发起来像是同时进行的
GIL全局解释器存在的原因是CPython解释器的内存管理不是线程安全的
同一个进程下多个线程不能实现并行但能实现并发,多个进程下的线程可以实现并行。
在IO密集的任务中
多线程优势更为明显(开启的消耗资源少)
在计算密集的任务中
多进程有优势(多CPU的优势可以提现)
# 计算密集型
from multiprocessing import Process
from threading import Thread
import os,time
def work():
res=0
for i in range(100):
res*=i
if __name__ == '__main__':
l=[]
print(os.cpu_count()) # 本机为8核
start=time.time()
for i in range(8):
# p=Process(target=work) #耗时9.252728939056396
p=Thread(target=work) #耗时35.369622230529785
l.append(p)
p.start()
for p in l:
p.join()
stop=time.time()
print('run time is %s' %(stop-start))
# IO密集型
from multiprocessing import Process
from threading import Thread
import threading
import os,time
def work():
time.sleep(2)
if __name__ == '__main__':
l=[]
print(os.cpu_count()) #本机为8核
start=time.time()
for i in range(600):
p=Process(target=work) #耗时4.699530839920044
# p=Thread(target=work) #耗时2.054128885269165
l.append(p)
p.start()
for p in l:
p.join()
stop=time.time()
print('run time is %s' %(stop-start))
GIL全局解释器锁与普通的互斥锁的区别
对于不同的数据,要想保证安全,需要加不同的锁处理
GIL并不能保证数据的安全,它是对Cpython解释器加锁,针对的是线程,让其无法并行,保证的是同一进程下多个线程间的安全
线程的互斥锁保证的是数据的安全性
from threading import Thread,Lock
import time
mutex=Lock()
n=100
def task():
global n
mutex.acquire() #如果不加自定义的锁,那么所有进程都得到了t=100的数据
t=n #确保t得到的是修改后的n
time.sleep(0.1)
n=t-1
mutex.release()
lis=[]
for i in range(100):
q=Thread(target=task)
q.start()
lis.append(q)
for i in lis:
i.join()
print(n)
死锁与递归锁
死锁就是两个线程或多个线程,得到了另一方需要获取的锁,而自身锁无法释放,导致线程的阻塞。
递归锁就是,可以重复获取的锁(自定义锁只能获取(acquire)一次),每一次获取都会计数+1,直到计数为0的时候,锁才会释放,其他线程才可以抢锁。
#死锁例子
from threading import Thread,Lock
import time
mutexA=Lock()
mutexB=Lock()
def task(name):
mutexA.acquire()#后来线程抢占了A锁,但是B锁未得到释放,无法获取
print('A get',name)
mutexB.acquire()
print('B get',name)
mutexA.release()
print('A lose',name)
mutexB.release()
print('B lose',name)
f1(name)
def f1(name):
mutexB.acquire()
print('B get',name)
time.sleep(0.1) #在IO的时候,其他的线程已经抢占了A锁,而B锁并未释放
mutexA.acquire()
print('A get',name)
mutexA.release()
print('A lose',name)
mutexB.release()
print('B lose',name)
if __name__ == '__main__':
for i in range(100):
p=Thread(target=task,args=(i,))
p.start()
#递归锁
from threading import Thread,RLock
import time
mutex=RLock()#生成一个递归锁对象
class MyThread(Thread):
def run(self):
self.f1()
self.f2()
def f1(self):
mutex.acquire()
print(self.name,1)
mutex.acquire()
print(self.name,2)
mutex.release()
mutex.release()
def f2(self):
mutex.acquire()
print(self.name,3)
time.sleep(0.5)
mutex.acquire()
print(self.name,4)
mutex.release()
mutex.release()
if __name__ == '__main__':
for i in range(100):
p = MyThread()
p.start()
信号量
#抢占厕所的例子
from threading import Thread,Semaphore
import time
sm=Semaphore(5)#设定信号量为5,只能有5个线程可以继续执行
def task(name):
with sm:
print('%s 正在上厕所')
time.sleep(5)
if __name__=='__main__':
for i in range(20):
p=Thread(target=task,args=(i,))
p.start()
event时间
from threading import Event,Thread
import time
event=Event()
def light():
print('红灯亮了')
time.sleep(5)
event.set() #解除阻塞
print('绿灯亮了')
def car(i):
print('%s 正在等红灯'%i)
event.wait() #阻塞
print('%s 通行'%i)
if __name__=='__main__':
t=Thread(target=light)
t.start()
for i in range(10):
c=Thread(target=car,args=(i,))
c.start()
线程queue
import queue
q=queue.Queue(3)#Queue按照队列,先进先出
q.put(1)
q.put(2)
q.put(3)
print(q.get())
print(q.get())
print(q.get())
q = queue.LifoQueue(5)#堆栈,Lifo,last in first out 先进后出
q.put(1)
q.put(2)
q.put(3)
q.put(4)
print(q.get())
q = queue.PriorityQueue()#PriorityQueue,优先级,数据越小,优先级越高
q.put((10,'a'))
q.put((-1,'b'))
q.put((100,'c'))
print(q.get())
print(q.get())
print(q.get())
# -1<10<100,所以顺序是(-1, 'b'),(10, 'a'),(100, 'c')