1. 程式人生 > >python多執行緒的一點理解

python多執行緒的一點理解

理解這個其實需要懂一點作業系統的知識,不得不感嘆學科之間其實很多都是有聯絡的。

其實多執行緒就比如泡麵的時候一邊燒開水一邊放醬料,兩不耽誤。

在單核cpu中執行緒通過併發來實現cpu運算資源的高效使用

import time, threading

# 新執行緒執行的程式碼:
def loop():
    print('thread %s is running...' % threading.current_thread().name)
    n = 0
    while n < 5:
        n = n + 1
        print('thread %s >>> %s' % (threading.current_thread().name, n))
        time.sleep(1)
    print('thread %s ended.' % threading.current_thread().name)

print('thread %s is running...' % threading.current_thread().name)
t = threading.Thread(target=loop, name='LoopThread')
t.start()
t.join()
print('thread %s ended.' % threading.current_thread().name)

 在多核cpu中由於每個核心都能跑一個執行緒,所以n個核心的cpu就能並行(注意這裡是並行了不再是併發了)n個執行緒

但是當python在多核cpu中卻存在一定的效能缺陷,這裡我們試著多開幾個執行緒看看

import threading, multiprocessing

def loop():
    x = 0
    while True:
        x = x ^ 1

if __name__=='__main__':
    for i in range(multiprocessing.cpu_count()):
        t = threading.Thread(target=loop)
        t.start()
        
        

這裡開了和cpu個數相等的執行緒,按道理來說1個執行緒的死迴圈可以跑滿1個核心,所有核心都跑一個迴圈cpu利用率肯定會爆炸吧

但是結果呢?

這裡就 涉及到了GIL(Global Interpreter Lock)全域性直譯器鎖在我查了各種資料後得出的結果就是,GIL是很久以前的

大佬為了防止執行緒崩潰設定的執行緒保護措施,簡單來說  就是執行緒執行前先加一個全域性鎖,但這個鎖只有1個,所以不管你

幾個核心都只能同時跑1個執行緒這個鎖不是python的特性,是直譯器CPython的特性,像JPython就沒有這個東西。

當時市面上還沒有出現多核cpu,摩爾定律還沒有失效,所以在當時這個東西還是很好用的,但隨著技術進步這

個慢慢就成了python的累贅

 

來看解決辦法,我瞭解到的方法是通過多程序來實現,試驗了一下,確實有用

import threading, multiprocessing
from multiprocessing import Process
def loop():
    x = 0
    while True:
        x = x ^ 1

if __name__=='__main__':
    for i in range(multiprocessing.cpu_count()):
        t = Process(target=loop)
        t.start()
        

 

 

 至於為什麼多程序可以實現,我在stackoverflow上看到的解答是,python為每個程序配一個直譯器,這樣下來

n個程序就有n個直譯器,每個程序一個主執行緒,GIL就加在這個主執行緒上,自然就突破了GIL的效能限制。

(至於更深入的原理可能需要等更加深入學習才能解釋出來)


這裡需要明確的是,雖然有GIL但是並不代表python的多執行緒就是雞肋,這個其實把我坑了有段時間,我一度以為python的多執行緒沒有用,但實際上多執行緒在解決IO密集型的任務上依舊有很大的優勢,畢竟人家就是為這個而生的。