多線程

threading 模塊

在 Python 中實現(xiàn)多線程奇徒,可以利用 threading 模塊中的 Thread 來實現(xiàn)尉间,其用法 mutliprocessing 模塊中的 Process 類偿乖。

th = threading.Thread([ target ],[ args ],[ kwargs ])

其中 target 參數(shù)是線程的目標(biāo)函數(shù),argskwargs 是目標(biāo)函數(shù)的參數(shù)哲嘲。如果不指定 target 參數(shù)贪薪,將會默認(rèn)調(diào)用線程對象中的 run 方法。
看一個例子:

from threading import Thread
from time import sleep

# 線程的執(zhí)行函數(shù)
def handlePrint(startRange):
    while True:
        startRange += 1
        print("我從 %d 開始輸出眠副,現(xiàn)在的輸出結(jié)果是 %d"%(startRange-1,startRange))
        sleep(0.5)

# 在主模塊中開啟線程
if __name__ == "__main__":
    for i in range(5):
        th = Thread(target = handlePrint,args = (i,))
        th.start()

運(yùn)行結(jié)果如下:

PS C:\Users\Charley\Desktop\py> python .\py.py
我從 0 開始輸出画切,現(xiàn)在的輸出結(jié)果是 1
我從 1 開始輸出,現(xiàn)在的輸出結(jié)果是 2
我從 2 開始輸出囱怕,現(xiàn)在的輸出結(jié)果是 3
我從 3 開始輸出霍弹,現(xiàn)在的輸出結(jié)果是 4
我從 4 開始輸出,現(xiàn)在的輸出結(jié)果是 5
我從 5 開始輸出娃弓,現(xiàn)在的輸出結(jié)果是 6
我從 3 開始輸出典格,現(xiàn)在的輸出結(jié)果是 4
我從 4 開始輸出,現(xiàn)在的輸出結(jié)果是 5
我從 2 開始輸出台丛,現(xiàn)在的輸出結(jié)果是 3
我從 1 開始輸出耍缴,現(xiàn)在的輸出結(jié)果是 2
我從 3 開始輸出,現(xiàn)在的輸出結(jié)果是 4
我從 2 開始輸出挽霉,現(xiàn)在的輸出結(jié)果是 3
我從 4 開始輸出防嗡,現(xiàn)在的輸出結(jié)果是 5
...

借助 threading 模塊下的 current_thread 函數(shù),可以獲取當(dāng)前的線程名:

from threading import Thread
from time import sleep

# 線程的執(zhí)行函數(shù)
def handlePrint(startRange):
    from threading import current_thread
    name = current_thread().name
    while True:
        startRange += 1
        print("我是 %s侠坎,現(xiàn)在的輸出結(jié)果是 %d"%(name,startRange))
        sleep(0.5)

# 在主模塊中開啟線程
if __name__ == "__main__":
    for i in range(5):
        th = Thread(target = handlePrint,args = (i,))
        th.start()

運(yùn)行結(jié)果為:

PS C:\Users\Charley\Desktop\py> python .\py.py
我是 Thread-1蚁趁,現(xiàn)在的輸出結(jié)果是 1
我是 Thread-2,現(xiàn)在的輸出結(jié)果是 2
我是 Thread-3硅蹦,現(xiàn)在的輸出結(jié)果是 3
我是 Thread-4荣德,現(xiàn)在的輸出結(jié)果是 4
我是 Thread-5闷煤,現(xiàn)在的輸出結(jié)果是 5
我是 Thread-2童芹,現(xiàn)在的輸出結(jié)果是 3
我是 Thread-1涮瞻,現(xiàn)在的輸出結(jié)果是 2
我是 Thread-3,現(xiàn)在的輸出結(jié)果是 4
我是 Thread-4假褪,現(xiàn)在的輸出結(jié)果是 5
我是 Thread-5署咽,現(xiàn)在的輸出結(jié)果是 6
我是 Thread-1,現(xiàn)在的輸出結(jié)果是 3
我是 Thread-4生音,現(xiàn)在的輸出結(jié)果是 6
我是 Thread-2宁否,現(xiàn)在的輸出結(jié)果是 4

擴(kuò)展線程類

我們也可以對線程類進(jìn)行擴(kuò)展,以實現(xiàn)一個獨立的模塊:

from threading import Thread
from time import sleep

# 擴(kuò)展線程類
class MyThread(Thread):
    def __init__(self,startRange):
        Thread.__init__(self)
        # 處理新建對象時傳入的參數(shù)
        self.__startRange = startRange

    # 聲明 run 方法
    def run(self):
        while True:
            print("我是 %s缀遍,我正在輸出 %d"%(self.name,self.__startRange))
            self.__startRange += 1
            sleep(1)

# 主模塊中開啟線程
if __name__ == '__main__':
    for i in range(5):
        th = MyThread(i)
        th.start()

運(yùn)行結(jié)果:

PS C:\Users\Charley\Desktop\py> python .\py.py
我是 Thread-1慕匠,我正在輸出 0
我是 Thread-2,我正在輸出 1
我是 Thread-3域醇,我正在輸出 2
我是 Thread-4台谊,我正在輸出 3
我是 Thread-5,我正在輸出 4
我是 Thread-1譬挚,我正在輸出 1
我是 Thread-2锅铅,我正在輸出 2
我是 Thread-4,我正在輸出 4
我是 Thread-5减宣,我正在輸出 5
我是 Thread-3盐须,我正在輸出 3
我是 Thread-2,我正在輸出 3
我是 Thread-1漆腌,我正在輸出 2
我是 Thread-4贼邓,我正在輸出 5
我是 Thread-3,我正在輸出 4
我是 Thread-5闷尿,我正在輸出 6

多個線程使用一份全局變量

有時候我們會在多個線程中操縱一個全局變量塑径,以提高性能(比如大數(shù)字累加),這樣會產(chǎn)生什么問題呢悠砚?我們可以看下面的代碼:

from threading import Thread

num = 0
# 讓 counter1 函數(shù)對 num 累加 100 萬次
def counter1():
    global num
    for i in range(1000000):
        num += 1
    print("counter1 計算出來的 num 的值是 %d"%num)

# 讓 counter2 函數(shù)對 num 累加 100 萬次
def counter2():
    global num
    for i in range(1000000):
        num += 1
    print("counter2 計算出來的 num 的值是 %d"%num)


# 主模塊中開啟線程
if __name__ == '__main__':
    th1 = Thread(target = counter1)
    th2 = Thread(target = counter2)
    th1.start()
    th2.start()
    th1.join()
    th2.join()
    print("主線程中獲取的 num 的值是 %d"%num)

運(yùn)行結(jié)果(每次運(yùn)行的結(jié)果可能都不一樣):

PS C:\Users\Charley\Desktop\py> python .\py.py
counter1 計算出來的 num 的值是 1082089
counter2 計算出來的 num 的值是 1183834
主線程中獲取的 num 的值是 1183834
PS C:\Users\Charley\Desktop\py>

這里并不是我們期望的 200 萬晓勇,為什么呢?
因為計算操作是由操作系統(tǒng)進(jìn)行調(diào)度的灌旧,操作系統(tǒng)并不會在等待一個函數(shù)甚至語句執(zhí)行完成后再調(diào)用后面的語句和函數(shù)绑咱,整個過程是不定的。有可能在 counter1 中對線程進(jìn)行了累加運(yùn)算枢泰,但并沒有賦值(只進(jìn)行了 num = num + 1 的后半部分就將控制權(quán)交給 counter2 函數(shù)了)描融,counter2 函數(shù)獲取控制權(quán)后,也進(jìn)行累加操作衡蚂,我們假定這次他進(jìn)行了一次完整的累加操作窿克。此后操作系統(tǒng)繼續(xù)進(jìn)行調(diào)度骏庸,執(zhí)行 counter1 未被執(zhí)行完成的賦值操作(等號左邊部分),該操作對 counter2 的上一次執(zhí)行結(jié)果進(jìn)行了覆蓋年叮,因此整個結(jié)果都是不穩(wěn)定的具被。
我們知道了,計算不穩(wěn)定的原因是多個線程相互搶占資源造成的只损。為了解決這個問題一姿,我們可以有以下的一些解決方案。

沖突線程延期執(zhí)行

我們可以讓沖突線程在前一個線程執(zhí)行之后再執(zhí)行跃惫,這個方案很簡單叮叹,只需稍微改變下調(diào)用 join 方法的位置:

from threading import Thread

num = 0
# 讓 counter1 函數(shù)對 num 累加 100 萬次
def counter1():
    global num
    for i in range(1000000):
        num += 1
    print("counter1 計算出來的 num 的值是 %d"%num)

# 讓 counter2 函數(shù)對 num 累加 100 萬次
def counter2():
    global num
    for i in range(1000000):
        num += 1
    print("counter2 計算出來的 num 的值是 %d"%num)


# 主模塊中開啟線程
if __name__ == '__main__':
    th1 = Thread(target = counter1)
    th2 = Thread(target = counter2)
    th1.start()
    th1.join()
    th2.start()
    th2.join()
    print("主線程中獲取的 num 的值是 %d"%num)

運(yùn)行結(jié)果:

PS C:\Users\Charley\Desktop\py> python .\py.py
counter1 計算出來的 num 的值是 1000000
counter2 計算出來的 num 的值是 2000000
主線程中獲取的 num 的值是 2000000
PS C:\Users\Charley\Desktop\py>

使用標(biāo)識變量區(qū)分不同線程

也可以使用標(biāo)識變量進(jìn)行區(qū)分:

from threading import Thread

num = 0
flag = 1
# 讓 counter1 函數(shù)對 num 累加 100 萬次
def counter1():
    global num,flag
    for i in range(1000000):
        num += 1
    flag = 0
    print("counter1 計算出來的 num 的值是 %d"%num)

# 讓 counter2 函數(shù)對 num 累加 100 萬次
def counter2():
    global num
    # counter2 線程一直輪詢等待 counter1 改變標(biāo)識變量
    while True:
        if not flag:
            for i in range(1000000):
                num += 1
            break
    print("counter2 計算出來的 num 的值是 %d"%num)


# 主模塊中開啟線程
if __name__ == '__main__':
    th1 = Thread(target = counter1)
    th2 = Thread(target = counter2)
    th1.start()
    th2.start()
    th1.join()
    th2.join()
    print("主線程中獲取的 num 的值是 %d"%num)

運(yùn)行結(jié)果:

PS C:\Users\Charley\Desktop\py> python .\py.py
counter1 計算出來的 num 的值是 1000000
counter2 計算出來的 num 的值是 2000000
主線程中獲取的 num 的值是 2000000
PS C:\Users\Charley\Desktop\py>

使用回調(diào)函數(shù)

也可以可以將回調(diào)函數(shù)作為參數(shù)傳入 counter1 函數(shù),counter1 累加完成后執(zhí)行:

from threading import Thread

num = 0
# 讓 counter1 函數(shù)對 num 累加 100 萬次
def counter1(callback):
    global num
    for i in range(1000000):
        num += 1
    print("counter1 計算出來的 num 的值是 %d"%num)
    callback()

# 讓 counter2 函數(shù)對 num 累加 100 萬次
def counter2():
    global num
    for i in range(1000000):
        num += 1
    print("counter2 計算出來的 num 的值是 %d"%num)

# 回調(diào)函數(shù)爆存,用來在 counter1 執(zhí)行完成后執(zhí)行
def callback():
    th2 = Thread(target = counter2)
    th2.start()
    th2.join()

# 主模塊中開啟線程
if __name__ == '__main__':
    th1 = Thread(target = counter1, args = (callback,))
    th1.start()
    th1.join()
    print("主線程中獲取的 num 的值是 %d"%num)

運(yùn)行結(jié)果:

PS C:\Users\Charley\Desktop\py> python .\py.py
counter1 計算出來的 num 的值是 1000000
counter2 計算出來的 num 的值是 2000000
主線程中獲取的 num 的值是 2000000
PS C:\Users\Charley\Desktop\py>

互斥鎖

針對多個線程搶占資源的問題蛉顽,上面給出了幾個比較“偏門”的解決方案,但都不是那么的“Python 范兒”先较,我們最好使用互斥鎖來解決這個問題携冤。
簡單理解,互斥鎖就是同一時間只能有一個線程占用資源拇泣,其他線程只有在該線程釋放掉資源后才能進(jìn)行操作噪叙,而在其他線程進(jìn)行操作時,也應(yīng)該首先對資源上鎖霉翔,這樣就不會因為相互搶占資源而造成不確定的情況了睁蕾。
使用互斥鎖,需要使用 threading 中的互斥鎖工具類 Lock债朵。有了互斥鎖類子眶,我們只需關(guān)心在合理的位置進(jìn)行上鎖和解鎖就可以了:

from threading import Thread,Lock

num = 0
# 讓 counter1 函數(shù)對 num 累加 100 萬次
def counter1():
    global num
    # 上鎖
    mutex.acquire()
    for i in range(1000000):
        num += 1
    # 解鎖
    mutex.release()
    print("counter1 計算出來的 num 的值是 %d"%num)

# 讓 counter2 函數(shù)對 num 累加 100 萬次
def counter2():
    global num
    # 上鎖
    mutex.acquire()
    for i in range(1000000):
        num += 1
    # 解鎖
    mutex.release()
    print("counter2 計算出來的 num 的值是 %d"%num)

# 創(chuàng)建一個互斥鎖對象
mutex = Lock()

# 主模塊中開啟線程
if __name__ == '__main__':
    th1 = Thread(target = counter1)
    th2 = Thread(target = counter2)
    th1.start()
    th2.start()
    th1.join()
    th2.join()
    print("主線程中獲取的 num 的值是 %d"%num)

運(yùn)行結(jié)果:

PS C:\Users\Charley\Desktop\py> python .\py.py
counter1 計算出來的 num 的值是 1000000
counter2 計算出來的 num 的值是 2000000
主線程中獲取的 num 的值是 2000000
PS C:\Users\Charley\Desktop\py>

local

上面主要解決了多線程之間相互搶占資源的問題,但你有沒有發(fā)現(xiàn)一個問題呢序芦?使用上面的方式臭杰,本質(zhì)都是在一個線程執(zhí)行完成后再執(zhí)行另一個線程,包括我們的互斥鎖谚中,都是在 counter1 計算完成后再解鎖渴杆,然后 counter2 才獲取了控制權(quán),繼續(xù)執(zhí)行宪塔。這樣雖然解決了搶占資源的問題磁奖,但性能卻不夠高,看上去是多個線程某筐,實際上只有一個線程在執(zhí)行比搭,下一個線程需要等前一個線程執(zhí)行完成后再執(zhí)行。(其實 Python 中的多線程同一時間也只有一個線程在執(zhí)行南誊,后面將會講到 GIL身诺,說明情況蜜托。)
為了解決這個問題,有個很簡單的方案:我們?yōu)槊總€線程定義一個各自的全局變量然后在主線程中匯總不就行了嗎霉赡?現(xiàn)在對程序進(jìn)行一些改進(jìn):

from threading import Thread

counter1_num = 0
counter2_num = 0
# 讓 counter1 函數(shù)對 num 累加 100 萬次
def counter1():
    global counter1_num
    for i in range(1000000):
        counter1_num += 1
    print("counter1 計算出來的 num 的值是 %d"%counter1_num)

# 讓 counter2 函數(shù)對 num 累加 100 萬次
def counter2():
    global counter2_num
    for i in range(1000000):
        counter2_num += 1
    print("counter2 計算出來的 num 的值是 %d"%counter2_num)

# 主模塊中開啟線程
if __name__ == '__main__':
    th1 = Thread(target = counter1)
    th2 = Thread(target = counter2)
    th1.start()
    th2.start()
    th1.join()
    th2.join()
    print("主線程中獲取的 num 的值是 %d"%(counter1_num + counter2_num))

運(yùn)行結(jié)果:

PS C:\Users\Charley\Desktop\py> python .\py.py
counter1 計算出來的 num 的值是 1000000
counter2 計算出來的 num 的值是 1000000
主線程中獲取的 num 的值是 2000000
PS C:\Users\Charley\Desktop\py>

除了使用這種方式橄务,我們還可以使用 threading 模塊中的一個 local 函數(shù),調(diào)用該函數(shù)返回一個對象同廉,每個線程中都可以使用這個對象仪糖,但是相對于每個線程柑司,這個對象都是一份獨立的副本迫肖,不會彼此覆蓋:

from threading import Thread,local

# 使用 local 函數(shù)創(chuàng)建一個變量
thead_local = local()
num = 0

# 讓 counter1 函數(shù)對 num 累加 100 萬次
def counter1():
    global num
    thead_local.num = 0
    for i in range(1000000):
        thead_local.num += 1
    print("counter1 計算出來的 num 的值是 %d"%thead_local.num)
    num += thead_local.num

# 讓 counter2 函數(shù)對 num 累加 100 萬次
def counter2():
    global num
    thead_local.num = 0
    for i in range(1000000):
        thead_local.num += 1
    print("counter2 計算出來的 num 的值是 %d"%thead_local.num)
    num += thead_local.num

# 主模塊中開啟線程
if __name__ == '__main__':
    th1 = Thread(target = counter1)
    th2 = Thread(target = counter2)
    th1.start()
    th2.start()
    th1.join()
    th2.join()
    print("主線程中獲取的 num 的值是 %d"%num)

運(yùn)行效果:

PS C:\Users\Charley\Desktop\py> python .\py.py
counter1 計算出來的 num 的值是 1000000
counter2 計算出來的 num 的值是 1000000
主線程中獲取的 num 的值是 2000000
PS C:\Users\Charley\Desktop\py>

GIL

GIL 也叫全局解釋器鎖,是 Python 語言在實現(xiàn)多線程時的一種機(jī)制攒驰,也是影響 Python 多線程性能的一個重要因素蟆湖。
在說這個問題之前,我們先來看下 Python 多線程在單核 CPU玻粪、多核 CPU 情況下的表現(xiàn)隅津。我們使用這樣一份代碼:

from threading import Thread
def target():
    while True:
        pass

if __name__ == "__main__":
    t1 = Thread(target = target)
    t2 = Thread(target = target)
    t1.start()
    t2.start()

1)單核 CPU 下的 CPU 使用情況:

單核CPU多線程情況.png

2)多核 CPU 下的 CPU 使用情況:

多核CPU多線程情況.png

我們看到,在單核 CPU 的情況下劲室,CPU 被利用的很充分(100%)伦仍,而在多核 CPU 的情況下,CPU 利用的并不是太充分很洋,還有許多空閑充蓝。這就是 Python 的 GIL 機(jī)制,也是影響多線程性能的一個地方喉磁。
與此同時谓苟,我們來看一下多核 CPU 情況下多進(jìn)程對 CPU 的利用情況:

from multiprocessing import Process
def target():
    while True:
        pass

if __name__ == "__main__":
    p1 = Process(target = target)
    p2 = Process(target = target)
    p1.start()
    p2.start()

看一下多進(jìn)程對 CPU 的利用率情況:

多核CPU多進(jìn)程情況.png

通過這幾個測驗可以看出:Python 語言中,多進(jìn)程比多線程對 CPU 的利用率更高协怒。
GIL 導(dǎo)致 Python 多線程的性能降低原因是:在此機(jī)制下涝焙,(Python 中的多線程并不是同時執(zhí)行的,同一時間只有一個線程在執(zhí)行孕暇,不管有多少 CPU 核心都是如此仑撞,執(zhí)行下一個線程需要等待上一個線程從 CPU 中調(diào)度出來后才能執(zhí)行。這就是 Python 中多線程性能較低的原因妖滔。
要解決多線程 GIL 的弊端隧哮,可以有下面兩種方式:

  • 盡量使用多進(jìn)程
  • 使用 C語言或者其他沒有 GIL 機(jī)制的語言構(gòu)建核心模塊,然后在 Python 中導(dǎo)入

總結(jié)

本文主要講到了 Python 語言中的多線程實現(xiàn)铛楣,大體有以下幾個知識點:

  • 多線程的創(chuàng)建
  • 擴(kuò)展 Thread
  • 多線程搶占資源的問題及集中解決方案
  • 互斥鎖
  • local
  • 多線程和多進(jìn)程的性能問題
  • GIL
  • GIL 問題的解決

完近迁。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市簸州,隨后出現(xiàn)的幾起案子鉴竭,更是在濱河造成了極大的恐慌歧譬,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搏存,死亡現(xiàn)場離奇詭異瑰步,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)璧眠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門缩焦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人责静,你說我怎么就攤上這事袁滥。” “怎么了灾螃?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵题翻,是天一觀的道長。 經(jīng)常有香客問我腰鬼,道長嵌赠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任熄赡,我火速辦了婚禮姜挺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘彼硫。我一直安慰自己炊豪,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布乌助。 她就那樣靜靜地躺著溜在,像睡著了一般。 火紅的嫁衣襯著肌膚如雪他托。 梳的紋絲不亂的頭發(fā)上掖肋,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天,我揣著相機(jī)與錄音赏参,去河邊找鬼志笼。 笑死,一個胖子當(dāng)著我的面吹牛把篓,可吹牛的內(nèi)容都是我干的纫溃。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼韧掩,長吁一口氣:“原來是場噩夢啊……” “哼紊浩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤坊谁,失蹤者是張志新(化名)和其女友劉穎费彼,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體口芍,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡箍铲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了鬓椭。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片颠猴。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖小染,靈堂內(nèi)的尸體忽然破棺而出翘瓮,到底是詐尸還是另有隱情,我是刑警寧澤氧映,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布春畔,位于F島的核電站,受9級特大地震影響岛都,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜振峻,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一臼疫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧扣孟,春花似錦烫堤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至利诺,卻和暖如春富蓄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背慢逾。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工立倍, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人侣滩。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓口注,卻偏偏與公主長得像,于是被迫代替她去往敵國和親君珠。 傳聞我的和親對象是個殘疾皇子寝志,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 線程和進(jìn)程 計算機(jī),用于計算的機(jī)器。計算機(jī)的核心是CPU材部,在現(xiàn)在多核心的電腦很常見了悠菜。為了充分利用cpu核心做計算...
    人世間閱讀 24,346評論 3 85
  • 前言:博主在剛接觸Python的時候時常聽到GIL這個詞悔醋,并且發(fā)現(xiàn)這個詞經(jīng)常和Python無法高效的實現(xiàn)多線程劃上...
    whypro閱讀 1,168評論 0 1
  • 前言:博主在剛接觸Python的時候時常聽到GIL這個詞芬骄,并且發(fā)現(xiàn)這個詞經(jīng)常和Python無法高效的實現(xiàn)多線程劃上...
    LazzMan閱讀 567評論 0 1
  • 首先引用廖老師的一句話:Python解釋器由于設(shè)計時有GIL全局鎖,導(dǎo)致了多線程無法利用多核鹦聪。多線程的并行在Pyt...
    玩阿軻睡妲己閱讀 1,625評論 0 19
  • 1.線程的基本概念 1.1 線程 線程是應(yīng)用程序最小的執(zhí)行單元账阻,線程與進(jìn)程類似,進(jìn)程可以看做程序的一次執(zhí)行泽本,而線程...
    XYZeroing閱讀 981評論 1 16