摘要:也提供多線程支持,而且中的線程并非是模擬出來的多線程,而是系統(tǒng)級別的標準庫提供了兩個模塊和。同一個變量,線程則會互相共享。例如多個線程對銀行中的某一個賬戶進行操作。但是實際情況是隨意切換線程。說到的多線程編程,就會繞不過。
該文章參考了http://www.liaoxuefeng.com/wi... 廖雪峰的教程。
一個進程至少有一個線程。
Python也提供多線程支持,而且Python中的線程并非是模擬出來的多線程,而是系統(tǒng)級別的Posix Thread.
Python標準庫提供了兩個模塊thread和threading。前者是低級庫,后者是高級庫。高級庫是對低級庫的封裝。
通常情況下,我們只需要使用threading高級庫就可以了。
我們只需要創(chuàng)建threading.Thread類,并傳入一個需要線程執(zhí)行的函數(shù)作為target即可。
import threading import time def loop(): count = 1 while count < 4: print "Hello" time.sleep(1) count += 1 if __name__ == "__main__": thread = threading.Thread(target=loop, name="LoopThread") thread.start() thread.join() current_thread = threading.current_thread() print current_thread.getName() print "LoopThread Ended"
上述代碼主進程默認會創(chuàng)建一個主線程。
上面的代碼中,我們用到了多個函數(shù)。
join()函數(shù):即讓主線程序等待子線程完成后繼續(xù)。
current_thread()函數(shù):獲取當(dāng)前線程的實例。
Lock 鎖同一個變量,進程會拷貝一份存于各個進程中,互不影響。
同一個變量,線程則會互相共享。這就會帶來一些問題。因為cpu對線程是隨意切換的。那么如果一個線程對某一個變量進行多步cpu操作的時候,如果不加鎖,那么可能會在線程進行到一半的時候,會被切換到其他線程,從而使得操作變亂。
一個典型的例子是“一存一取”的場景。
例如多個線程對銀行中的某一個賬戶進行操作。一個線程需要對賬戶進行一存一取某一個金額的操作才會讓賬戶平衡。
但是多個線程對該賬戶進行操作的時候,且它們操作的金額經(jīng)常是不一樣的,那么最終的賬戶很可能是不平衡的。
thread 1: -100 thread 1: +100 thread 1: -100 thread 1: +100 thread 2: -200 thread 2: +200 thread 2: -200 thread 2: +200
上述描述了兩個線程按順序互補干擾地對某一個賬戶進行操作。
但是實際情況是cpu隨意切換線程。上述操作是打亂的,例如
thread 1: -100 thread 2: -200 thread 2: +200 ...
此時,我們發(fā)現(xiàn)賬戶并不是平衡的。
如果解決呢?我們需要對每一個thread的一存一取操作加一把鎖。即改賬戶變量必須是讓一個線程先進行完整的一存一取操作后,才能被其他線程所操作。
我們可以將要上鎖的代碼包裹起來,即:
lock.acquire() num = num + n num = num - n print num lock.release()
當(dāng)然,lock可以對資源的獲取和釋放,那么我們也可以用with關(guān)鍵字。
with lock: num = num + n num = num - n print num死鎖 deadlock
死鎖的發(fā)生往往是兩個線程各自占用了對方所需要用到的資源而都在等待對方釋放資源而造成的。
遇見死鎖后,程序則會一直暫停在那里。直到系統(tǒng)將它們關(guān)閉。
說到Python的多線程編程,就會繞不過GIL。那么GIL又是什么鬼呢?
GIL據(jù)說是Python中hardest的問題,想要徹底了解GIL,必須要對操作系統(tǒng)設(shè)計、多線程編程、C語言、解釋器設(shè)計和CPython解釋器的實現(xiàn)有著非常徹底的理解。
據(jù)廖雪峰中的教程中描述:
Python中的線程雖然是真正的線程,但是解釋器執(zhí)行代碼的時候,會有一個GIL鎖(Global Interpreter Lock). 任何Python線程執(zhí)行前,必須先獲得GIL鎖。然后,每執(zhí)行100條字節(jié)碼,解釋器就會自動釋放GIL鎖,讓別的線程有機會執(zhí)行。這個GIL全局鎖實際上把所有線程的執(zhí)行代碼都給上了鎖。因此,多線程在Python中只能交替進行,即使100個線程跑在100核CPU上,也只能用到1個核心。
GIL是Python解釋器設(shè)計的歷史遺留問題,通常我們用的解釋器是官方實現(xiàn)徹底CPython。
更多關(guān)于GIL設(shè)計的歷史淵源,可以閱讀:
http://cenalulu.github.io/pyt...
http://www.oschina.net/transl...
那么是不是Python就是不能利用多核處理器任務(wù)了呢?我們之前學(xué)到過多進程編程,每一個進程都有一個獨立的GIL鎖,各進程互不影響。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/38366.html
摘要:試想,在多線程服務(wù)器中,多個線程同時處理不同客戶端發(fā)送的不同請求時,每個線程看到的對象必然不同。多線程服務(wù)器會創(chuàng)建一個線程池,再從線程池中選擇一個線程用于處理接收到的請求。 框架 Django flask flask是一個輕量的web開發(fā)應(yīng)用示例開發(fā)一個小應(yīng)用 from flask import Flask app = Flask(__name__) @app.route(/) d...
摘要:為了避免改亂為,我們在前面已經(jīng)提到說要加鎖。僅供一個線程使用,線程間相互不影響。例如下列程序中函數(shù)中定義的變量就是局部變量。所有綁定的參數(shù)都是線程隔離的。下面展示一下代碼創(chuàng)建一個全局的對象初始化一個線程內(nèi)變量,該變量線程間互不影響。 我們在編寫多線程程序的時候,往往會遇到兩種類型的變量。 一種是全局變量,多個線程共享。為了避免改亂為,我們在前面已經(jīng)提到說要加鎖。 一種是局部變量。僅供...
摘要:首發(fā)于我的博客線程池進程池網(wǎng)絡(luò)編程之同步異步阻塞非阻塞后端掘金本文為作者原創(chuàng),轉(zhuǎn)載請先與作者聯(lián)系。在了解的數(shù)據(jù)結(jié)構(gòu)時,容器可迭代對象迭代器使用進行并發(fā)編程篇二掘金我們今天繼續(xù)深入學(xué)習(xí)。 Python 算法實戰(zhàn)系列之棧 - 后端 - 掘金原文出處: 安生??? 棧(stack)又稱之為堆棧是一個特殊的有序表,其插入和刪除操作都在棧頂進行操作,并且按照先進后出,后進先出的規(guī)則進行運作。 如...
摘要:開頭正式開啟我入職的里程,現(xiàn)在已是工作了一個星期了,這個星期算是我入職的過渡期,算是知道了學(xué)校生活和工作的差距了,總之,盡快習(xí)慣這種生活吧。當(dāng)時是看的廖雪峰的博客自己也用做爬蟲寫過幾篇博客,不過有些是在前人的基礎(chǔ)上寫的。 showImg(https://segmentfault.com/img/remote/1460000010867984); 開頭 2017.08.21 正式開啟我...
閱讀 3542·2021-11-25 09:43
閱讀 2765·2021-09-22 15:54
閱讀 652·2019-08-30 15:55
閱讀 1034·2019-08-30 15:55
閱讀 2076·2019-08-30 15:55
閱讀 1804·2019-08-30 15:53
閱讀 3535·2019-08-30 15:52
閱讀 2107·2019-08-30 12:55