全局解釋鎖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. (However, since the GIL 
exists, other features have grown to depend on the guarantees that it enforces.)
'''
結論:在Cpython解釋器中,同一個進程下開啓的多線程,同一時刻只能有一個線程執行,沒法利用多核優點

 前言: python

- GIL其實就是一把互斥鎖(犧牲了效率可是保證了數據的安全)。
- 線程是執行單位,可是不能直接運行,須要先拿到python解釋器解釋以後才能被cpu執行
- 同一時刻同一個進程內多個線程沒法實現並行,可是能夠實現併發

  一.GIL全局解釋器 垃圾回收機制:安全

- 垃圾回收機制也是一個任務,跟你的代碼不是串行運行,若是是串行會明顯有卡頓
- 這個垃圾回收究竟是開進程仍是開線程?確定是線程,線程確定也是一段代碼,因此想運行也必需要拿到python解釋器
沒有GIL全局解釋器鎖 他只是對線程加鎖 不是對數據
運行垃圾回收機制:引用計數 1,必須先拿到python 解釋器---> 2.python 進程下的多個線程是併發。若此時你想建立一個  a = 1 cpu運行速度是很是快的 
那麼就會引起 其餘線程垃圾回收機制掃描把我剛建立的內存清理掉 因此必須設置GIL全局解釋器鎖
也就意味着在Cpython解釋器上有一把GIL全局解釋器鎖

 二. 多線程

1.python中的多線程到底有沒有用?
  1、數據密集型
  2、IO密集型

#### 1.python中的多線程到底有沒有用?

單核狀況下:四個任務

多核狀況下:四個任務

計算密集型:一個任務算十秒,四個進程和四個線程,確定是進程快

IO密集型:任務都是純io狀況下,線程開銷比進程小,確定是線程好

 

1、數據密集型
def task(): res = 0 for i in range(100000000): res = res*i if __name__ == '__main__': print(os.cpu_count()) #本機內核 p_list=[] start_time= time.time() for i in range(4): p = Process(target=task) # 進程運行時間爲10.636553287506104 # p = Thread(target= task) # 線程運行時間爲19.97660756111145 p.start() p_list.append(p) for p in p_list: p.join() end_time = time.time() print('運行時間爲%s'% (end_time-start_time))

  

""
2、IO密集型
def work():
    time.sleep(3)
if __name__ == '__main__':
    print(os.cpu_count())
    start_time =time.time()
    p_list=[]
    for i in range(4):
        # p = Process(target= work)   # run is total_time7.271259546279907
        p = Thread(target= work)    # run is total_time3.002392053604126
        p.start()
        p_list.append(p)
    for p in p_list:
        p.join()
    end_time =time.time()
    print('run is total_time%s'%(end_time-start_time))

  3、全局鎖與普通鎖併發

  

對於不一樣的數據,要想保證安全,須要加不一樣的鎖處理
GIL並不能保證數據的安全,它是對Cpython解釋器加鎖,針對的是線程
保證的是同一個進程下多個線程之間的安全

  

"""
from threading import Thread

import os
import time
from threading import Lock
mutex = Lock()
num = 100
def task():
    global num
    mutex.acquire()     #搶鎖
    temp = num
    time.sleep(0.1)
    num = temp-1
    mutex.release()  # 釋放鎖 開始一個


if __name__ == '__main__':
    p_lsit=[]
    for i in range(10):

        p = Thread(target=task)
        p.start()
        p_lsit.append(p)
    for p in p_lsit:
        p.join()
    print(num)  # 90 至關於10個線程同時去搶100票 必需要確保一個數據同時被10個進程同時搶 鎖是起到保護做用 取完一個減一個

  4、.死鎖與遞歸鎖(瞭解)app

自定義鎖一次acquire必須對應一次release,不能連續acquiredom

遞歸鎖能夠連續的acquire,每acquire一次計數加一ui

import time
from threading import Thread,RLock

mutexA = mutexB= RLock()    # 遞歸鎖RLock
class Mythread(Thread):

    def run(self):
        self.fn1()
        self.fn2()

    def fn1(self):
        #設置鎖
        mutexA.acquire()
        print('%s 搶到A鎖了'%self.name)
        mutexB.acquire()
        print('%s 搶到B鎖了'%self.name)
        mutexB.release()
        print('%s釋放了B鎖'%self.name)
        mutexA.release()
        print('%s釋放了A鎖'%self.name)

    def fn2(self):
        mutexB.acquire()
        print('%s 搶到A鎖了' % self.name)
        time.sleep(1)
        mutexA.acquire()
        print('%s 搶到B鎖了' % self.name)
        mutexA.release()
        print('%s釋放了B鎖' % self.name)
        mutexB.release()
        print('%s釋放了A鎖' % self.name)


if __name__ == '__main__':
    for i in range(100):
        t = Mythread()
        t.start()

  

五.Event事件

一些線程須要等待另一些線程運行完畢才能運行,相似於發射信號同樣spa

from threading import Thread

from threading import Event

import time
event = Event()    #造了一個綠燈
def light():
    print('等紅燈')
    time.sleep(3)
    event.set() # 解除阻塞而且給 event發了一個信號
    print('綠燈亮了')

def car(i):
    print('%s燈紅燈'%i)
    event.wait()
    print('%s綠燈了,加油門'%i)

if __name__ == '__main__':
    t = Thread(target=light)
    t.start()

    p_list=[]
    for i in range(5):
        p = Thread(target=car,args=(i,))
        p.start()

# 等紅燈
# 0燈紅燈
# 1燈紅燈
# 2燈紅燈
# 3燈紅燈
# 4燈紅燈
# 綠燈亮了
# 0綠燈了,加油門
# 1綠燈了,加油門
# 3綠燈了,加油門
# 4綠燈了,加油門
# 2綠燈了,加油門#

  

六.信號量(瞭解)

自定義的互斥鎖若是是一個廁所,那麼信號量就至關於公共廁所,門口掛着多個廁所的鑰匙。搶和釋放跟互斥鎖一致線程

普通互斥鎖, 獨立衛生間 全部人只有一把鎖
信號量 ,公共衛生間 有多少個坑 就有多少把鎖
"""
from threading import Thread
from threading import Semaphore #信號量
import time
import random
sm = Semaphore(5)    #一個公共廁所造了5個坑 在廁所外放了5把鎖

def task(name):
    sm.acquire()    # 釋放信號鎖

    print('%s正在蹲坑'%name)
    time.sleep(random.randint(1, 3))
    sm.release()

for i in range(20):
    t = Thread(target= task,args=('%s傘兵'%i,))
    t.start()

 

0傘兵正在蹲坑
1傘兵正在蹲坑
2傘兵正在蹲坑
3傘兵正在蹲坑
4傘兵正在蹲坑
此時5我的中 有一我的好了 同時釋放了一把鎖
5傘兵正在蹲坑
前面5個好了兩個釋放給 6,7
6傘兵正在蹲坑
7傘兵正在蹲坑

8傘兵正在蹲坑
9傘兵正在蹲坑
10傘兵正在蹲坑
11傘兵正在蹲坑

12傘兵正在蹲坑
13傘兵正在蹲坑
14傘兵正在蹲坑
15傘兵正在蹲坑

16傘兵正在蹲坑
17傘兵正在蹲坑
18傘兵正在蹲坑
19傘兵正在蹲坑

  

  

七.線程queue

同一個進程下的線程數據都是共享的爲何還要用queue?queue自己自帶鎖的功能,可以保證數據的安全code

  

import queue

"""
1.普通q
2.堆棧。先進後出q
3.優先級q

"""
q = queue.Queue(3)
q.put(1)
q.put(2)

q.put(3)
print(q.get())
print(q.get())
print(q.get())  # 取值
——————》》》
1
2
3 q = queue.LifoQueue(5) q.put(1) q.put(2) q.put(3) q.put(4) q.put(5) print(q.get()) print(q.get()) print(q.get()) print(q.get()) print(q.get()) # 先進後出 和堆棧同樣
——————》》》

5
4
3
2
1

q = queue.PriorityQueue(3)
q.put(100,"q")
q.put(20,"t")
q.put(-1,'s')

print(q.get())
print(q.get())
print(q.get())  # 優先級是按照數字從小到大排列的
————————》》》

-120100

相關文章
相關標籤/搜索