1. 程式人生 > >python GIL鎖 鎖 線程池 生產者消費模型

python GIL鎖 鎖 線程池 生產者消費模型

lease 內置 lock NPU local release 解釋器 ask pool

python的GIL 鎖

  python內置的一個全局解釋器鎖 , 鎖的作用就是保證同一時刻一個進程中只有一個線程可以被cpu調度

為什麽有這把GIL鎖?

  python語言的創始人在開發這門語言時 , 目的快速把語言開發出來 , 如果加上GIL鎖(C語言加鎖) , 切換時按照100條字節指令來進行線程間的切換

鎖 :

  1.鎖 : Lock(1次放1個)

    線程安全 , 多線程操作時 , 內部會讓所有線程排隊處理 , 如 : list / dict / Queue

    線程不安全 + 人 =>排隊處理

    需求:

      a:創建100個進程 , 在列表中追加8

      b:創建100個線程

        v = []

        鎖

        把自己添加到列表中

        在讀取列表的最後一個

        解鎖

import threading
import time

v = []
lock = threading.Lock()

def func(arg):
    lock.acquire()
    v.append(arg)
    time.sleep(0.01)
    m = v[-1]
    print(arg,m)
    lock.release()


for i in range(10):
    t =threading.Thread(target=func,args=(i,))
    t.start()

  2.鎖 : RLock(1次放1個)

import threading
import time

v = []
lock = threading.RLock()
def func(arg):
    lock.acquire()
    lock.acquire()

    v.append(arg)
    time.sleep(0.01)
    m = v[-1]
    print(arg,m)

    lock.release()
    lock.release()


for i in range(10):
    t =threading.Thread(target=func,args=(i,))
    t.start()

  3鎖 : BoundedSemaphore (1次放N個) 信號量

import time
import threading

lock = threading.BoundedSemaphore(3)
def func(arg):
    lock.acquire()
    print(arg)
    time.sleep(1)
    lock.release()


for i in range(20):
    t =threading.Thread(target=func,args=(i,))
    t.start()

  4.鎖 : Condition (1次方法x個)

import time
import threading

lock = threading.Condition()


def func(arg):
    print(線程進來了)
    lock.acquire()
    lock.wait() # 加鎖

    print(arg)
    time.sleep(1)

    lock.release()


for i in range(10):
    t =threading.Thread(target=func,args=(i,))
    t.start()

while True:
    inp = int(input(>>>))

    lock.acquire()
    lock.notify(inp)
    lock.release()

  5.鎖 : Event(1次放所有)

 

import time
import threading

lock = threading.Event()


def func(arg):
    print(線程來了)
    lock.wait() # 加鎖:紅燈
    print(arg)


for i in range(10):
    t =threading.Thread(target=func,args=(i,))
    t.start()

input(">>>>")
lock.set() # 綠燈


lock.clear() # 再次變紅燈

for i in range(10):
    t =threading.Thread(target=func,args=(i,))
    t.start()

input(">>>>")
lock.set()

以上例子 : 線程安全 , 列表和字典線程安全

    為什麽要加鎖?

      非線程安全

      控制一段代碼

6. threading.local

    作用 : 內部自動會為每個線程維護一個空間(字典) 用於當前存取屬於自己的值 , 保證線程之間的數據隔離

      

      {
        線程ID: {...}
        線程ID: {...}
        線程ID: {...}
        線程ID: {...}
      }

import time
import threading

v = threading.local()

def func(arg):
    # 內部會為當前線程創建一個空間用於存儲:phone=自己的值
    v.phone = arg
    time.sleep(2)
    print(v.phone,arg) # 去當前線程自己空間取值

for i in range(10):
    t =threading.Thread(target=func,args=(i,))
    t.start()

原理方法如下

import time
import threading

DATA_DICT = {}

def func(arg):
    ident = threading.get_ident()
    DATA_DICT[ident] = arg
    time.sleep(1)
    print(DATA_DICT[ident],arg)


for i in range(10):
    t =threading.Thread(target=func,args=(i,))
    t.start()

7. 線程池

from concurrent.futures import ThreadPoolExecutor
import time

def task(a1,a2):
    time.sleep(2)
    print(a1,a2)

# 創建了一個線程池(最多5個線程)
pool = ThreadPoolExecutor(5)

for i in range(40):
    # 去線程池中申請一個線程,讓線程執行task函數。
    pool.submit(task,i,8)

8.生產者消費者模型

  三部件 :

      生產者

          隊列 , 先進先出

          擴展 : 棧 , 後進先出

      消費者

  問 : 生產者消費者模型解決了啥問題? 不用一直等待問題

import time
import queue
import threading
q = queue.Queue() # 線程安全

def producer(id):
    """
    生產者
    :return:
    """
    while True:
        time.sleep(2)
        q.put(包子)
        print(廚師%s 生產了一個包子 %id )

for i in range(1,4):
    t = threading.Thread(target=producer,args=(i,))
    t.start()


def consumer(id):
    """
    消費者
    :return:
    """
    while True:
        time.sleep(1)
        v1 = q.get()
        print(顧客 %s 吃了一個包子 % id)

for i in range(1,3):
    t = threading.Thread(target=consumer,args=(i,))
    t.start()

鎖  線程  線程池  threading.local  生成著消費者模型

概念性理解 配合代碼

  

          

python GIL鎖 鎖 線程池 生產者消費模型