當前位置:首頁 » 編程語言 » python多核編程

python多核編程

發布時間: 2022-09-21 16:05:11

python多線程不能使用多核嗎

首先,語言應該在什麼級別支持多線程。C 通過操作系統的 preemptive scheler 支持多線程,同時提供 critical section, wait/notify 這樣的同步機制。問題在於,這樣的同步機制太低級,在實際應用中經常需要封裝為高級的同步機制,比如多線程的生產者-消費者隊列。高級動態語言的設計者面臨三個選擇:

在語言中直接提供類似 C 的機制(Java);
設計良好的 C 介面,在同一進程中運行多個虛擬機,利用 C 把低級同步機制封裝成多虛擬機之間的高級同步機制(Lua),或者把多線程優化完全封裝在一個 API 之內(比如 Intel MKL 的各種多核演算法)。
多進程。
方法 1 是得不償失的。因為低級同步機制的優勢在於效率,而考慮效率就必須考慮諸如 L1/L2/L3 cache 實效之類的底層情況。這對於解釋執行的語言(即使有 JIT)來說是無法控制的。所以高級動態語言提供底層同步機制實際沒有必要。應該多走方法 2 和 3。其中又以 2 最為靈活。
移除 GIL 難嗎?不難,因為根本沒有必要移除。如果 Python 能在一個進程中初始化多個 VM,同時其標准庫在 C 級別做出足夠多的常用多核優化就沒有問題。Python 其實是希望實現另一個功能,非同步操作。盡管非同步操作和並行計算都可以通過多線程來完成,但是其實前者更加適合用協程或者用戶級線程來完成。但是 Python 是 stackful 實現,也就是 byte code 借用 C runtime stack 來維護自己的運行狀態。這種機制的弱點就是不容易用跨平台的方式來實現協程,所以利用 OS 多線程加 GIL 也就成了模擬協程語意的妥協手段。
補充一下。C 的線程和線程同步機制雖然底層,但是只有這種機制才能覆蓋所有 use case。而其它的高層抽象只能適合某種 case。所以,當我說高級動態語言需要高級的線程操作時,我的隱含意思是這種語言同時還要有和 C 進行良好的互操作來隨時擴展這種抽象。

② 有兩個獨立的任務,想分配不同數量的邏輯處理器去同時並行處理這兩個獨立任務,python可以實現嗎

python並沒有真正意義上的多線程,如果是計算型任務可以考慮多進程或者換個編程語言,如果是io型的python的多線程或者協程都可以。最好不要使用python進行多任務,python並不能真正發揮cpu多核優勢

③ python多線程對多核的利用

GIL 與 Python 線程的糾葛
GIL 是什麼東西?它對我們的 python 程序會產生什麼樣的影響?我們先來看一個問題。運行下面這段 python 程序,CPU 佔用率是多少?
# 請勿在工作中模仿,危險:)
def dead_loop():
while True:
pass

dead_loop()

答案是什麼呢,佔用 100% CPU?那是單核!還得是沒有超線程的古董 CPU。在我的雙核 CPU 上,這個死循環只會吃掉我一個核的工作負荷,也就是只佔用 50% CPU。那如何能讓它在雙核機器上佔用 100% 的 CPU 呢?答案很容易想到,用兩個線程就行了,線程不正是並發分享 CPU 運算資源的嗎。可惜答案雖然對了,但做起來可沒那麼簡單。下面的程序在主線程之外又起了一個死循環的線程
import threading

def dead_loop():
while True:
pass

# 新起一個死循環線程
t = threading.Thread(target=dead_loop)
t.start()

# 主線程也進入死循環
dead_loop()

t.join()

按道理它應該能做到佔用兩個核的 CPU 資源,可是實際運行情況卻是沒有什麼改變,還是只佔了 50% CPU 不到。這又是為什麼呢?難道 python 線程不是操作系統的原生線程?打開 system monitor 一探究竟,這個佔了 50% 的 python 進程確實是有兩個線程在跑。那這兩個死循環的線程為何不能占滿雙核 CPU 資源呢?其實幕後的黑手就是 GIL。
GIL 的迷思:痛並快樂著
GIL 的全稱為 Global Interpreter Lock ,意即全局解釋器鎖。在 Python 語言的主流實現 CPython 中,GIL 是一個貨真價實的全局線程鎖,在解釋器解釋執行任何 Python 代碼時,都需要先獲得這把鎖才行,在遇到 I/O 操作時會釋放這把鎖。如果是純計算的程序,沒有 I/O 操作,解釋器會每隔 100 次操作就釋放這把鎖,讓別的線程有機會執行(這個次數可以通過sys.setcheckinterval 來調整)。所以雖然 CPython 的線程庫直接封裝操作系統的原生線程,但 CPython 進程做為一個整體,同一時間只會有一個獲得了 GIL 的線程在跑,其它的線程都處於等待狀態等著 GIL 的釋放。這也就解釋了我們上面的實驗結果:雖然有兩個死循環的線程,而且有兩個物理 CPU 內核,但因為 GIL 的限制,兩個線程只是做著分時切換,總的 CPU 佔用率還略低於 50%。
看起來 python 很不給力啊。GIL 直接導致 CPython 不能利用物理多核的性能加速運算。那為什麼會有這樣的設計呢?我猜想應該還是歷史遺留問題。多核 CPU 在 1990 年代還屬於類科幻,Guido van Rossum 在創造 python 的時候,也想不到他的語言有一天會被用到很可能 1000+ 個核的 CPU 上面,一個全局鎖搞定多線程安全在那個時代應該是最簡單經濟的設計了。簡單而又能滿足需求,那就是合適的設計(對設計來說,應該只有合適與否,而沒有好與不好)。怪只怪硬體的發展實在太快了,摩爾定律給軟體業的紅利這么快就要到頭了。短短 20 年不到,代碼工人就不能指望僅僅靠升級 CPU 就能讓老軟體跑的更快了。在多核時代,編程的免費午餐沒有了。如果程序不能用並發擠干每個核的運算性能,那就意謂著會被淘汰。對軟體如此,對語言也是一樣。那 Python 的對策呢?
Python 的應對很簡單,以不變應萬變。在最新的 python 3 中依然有 GIL。之所以不去掉,原因嘛,不外以下幾點:
欲練神功,揮刀自宮:
CPython 的 GIL 本意是用來保護所有全局的解釋器和環境狀態變數的。如果去掉 GIL,就需要多個更細粒度的鎖對解釋器的眾多全局狀態進行保護。或者採用 Lock-Free 演算法。無論哪一種,要做到多線程安全都會比單使用 GIL 一個鎖要難的多。而且改動的對象還是有 20 年歷史的 CPython 代碼樹,更不論有這么多第三方的擴展也在依賴 GIL。對 Python 社區來說,這不異於揮刀自宮,重新來過。
就算自宮,也未必成功:
有位牛人曾經做了一個驗證用的 CPython,將 GIL 去掉,加入了更多的細粒度鎖。但是經過實際的測試,對單線程程序來說,這個版本有很大的性能下降,只有在利用的物理 CPU 超過一定數目後,才會比 GIL 版本的性能好。這也難怪。單線程本來就不需要什麼鎖。單就鎖管理本身來說,鎖 GIL 這個粗粒度的鎖肯定比管理眾多細粒度的鎖要快的多。而現在絕大部分的 python 程序都是單線程的。再者,從需求來說,使用 python 絕不是因為看中它的運算性能。就算能利用多核,它的性能也不可能和 C/C++ 比肩。費了大力氣把 GIL 拿掉,反而讓大部分的程序都變慢了,這不是南轅北轍嗎。
難道 Python 這么優秀的語言真的僅僅因為改動困難和意義不大就放棄多核時代了嗎?其實,不做改動最最重要的原因還在於:不用自宮,也一樣能成功!
其它神功
那除了切掉 GIL 外,果然還有方法讓 Python 在多核時代活的滋潤?讓我們回到本文最初的那個問題:如何能讓這個死循環的 Python 腳本在雙核機器上佔用 100% 的 CPU?其實最簡單的答案應該是:運行兩個 python 死循環的程序!也就是說,用兩個分別占滿一個 CPU 內核的 python 進程來做到。確實,多進程也是利用多個 CPU 的好方法。只是進程間內存地址空間獨立,互相協同通信要比多線程麻煩很多。有感於此,Python 在 2.6 里新引入了 multiprocessing這個多進程標准庫,讓多進程的 python 程序編寫簡化到類似多線程的程度,大大減輕了 GIL 帶來的不能利用多核的尷尬。
這還只是一個方法,如果不想用多進程這樣重量級的解決方案,還有個更徹底的方案,放棄 Python,改用 C/C++。當然,你也不用做的這么絕,只需要把關鍵部分用 C/C++ 寫成 Python 擴展,其它部分還是用 Python 來寫,讓 Python 的歸 Python,C 的歸 C。一般計算密集性的程序都會用 C 代碼編寫並通過擴展的方式集成到 Python 腳本里(如 NumPy 模塊)。在擴展里就完全可以用 C 創建原生線程,而且不用鎖 GIL,充分利用 CPU 的計算資源了。不過,寫 Python 擴展總是讓人覺得很復雜。好在 Python 還有另一種與 C 模塊進行互通的機制 : ctypes
利用 ctypes 繞過 GIL
ctypes 與 Python 擴展不同,它可以讓 Python 直接調用任意的 C 動態庫的導出函數。你所要做的只是用 ctypes 寫些 python 代碼即可。最酷的是,ctypes 會在調用 C 函數前釋放 GIL。所以,我們可以通過 ctypes 和 C 動態庫來讓 python 充分利用物理內核的計算能力。讓我們來實際驗證一下,這次我們用 C 寫一個死循環函數
extern"C"
{
void DeadLoop()
{
while (true);
}
}

用上面的 C 代碼編譯生成動態庫 libdead_loop.so (Windows 上是 dead_loop.dll)
,接著就要利用 ctypes 來在 python 里 load 這個動態庫,分別在主線程和新建線程里調用其中的 DeadLoop
from ctypes import *
from threading import Thread

lib = cdll.LoadLibrary("libdead_loop.so")
t = Thread(target=lib.DeadLoop)
t.start()

lib.DeadLoop()

這回再看看 system monitor,Python 解釋器進程有兩個線程在跑,而且雙核 CPU 全被占滿了,ctypes 確實很給力!需要提醒的是,GIL 是被 ctypes 在調用 C 函數前釋放的。但是 Python 解釋器還是會在執行任意一段 Python 代碼時鎖 GIL 的。如果你使用 Python 的代碼做為 C 函數的 callback,那麼只要 Python 的 callback 方法被執行時,GIL 還是會跳出來的。比如下面的例子:
extern"C"
{
typedef void Callback();
void Call(Callback* callback)
{
callback();
}
}

from ctypes import *
from threading import Thread

def dead_loop():
while True:
pass

lib = cdll.LoadLibrary("libcall.so")
Callback = CFUNCTYPE(None)
callback = Callback(dead_loop)

t = Thread(target=lib.Call, args=(callback,))
t.start()

lib.Call(callback)

注意這里與上個例子的不同之處,這次的死循環是發生在 Python 代碼里 (DeadLoop 函數) 而 C 代碼只是負責去調用這個 callback 而已。運行這個例子,你會發現 CPU 佔用率還是只有 50% 不到。GIL 又起作用了。
其實,從上面的例子,我們還能看出 ctypes 的一個應用,那就是用 Python 寫自動化測試用例,通過 ctypes 直接調用 C 模塊的介面來對這個模塊進行黑盒測試,哪怕是有關該模塊 C 介面的多線程安全方面的測試,ctypes 也一樣能做到。
結語
雖然 CPython 的線程庫封裝了操作系統的原生線程,但卻因為 GIL 的存在導致多線程不能利用多個 CPU 內核的計算能力。好在現在 Python 有了易經筋(multiprocessing), 吸星大法(C 語言擴展機制)和獨孤九劍(ctypes),足以應付多核時代的挑戰,GIL 切還是不切已經不重要了,不是嗎。

④ 如何使用Python實現並發編程

多線程幾乎是每一個程序猿在使用每一種語言時都會首先想到用於解決並發的工具(JS程序員請迴避),使用多線程可以有效的利用CPU資源(Python例外)。然而多線程所帶來的程序的復雜度也不可避免,尤其是對競爭資源的同步問題。

然而在python中由於使用了全局解釋鎖(GIL)的原因,代碼並不能同時在多核上並發的運行,也就是說,Python的多線程不能並發,很多人會發現使用多線程來改進自己的Python代碼後,程序的運行效率卻下降了,這是多麼蛋疼的一件事呀!如果想了解更多細節,推薦閱讀這篇文章。實際上使用多線程的編程模型是很困難的,程序員很容易犯錯,這並不是程序員的錯誤,因為並行思維是反人類的,我們大多數人的思維是串列(精神分裂不討論),而且馮諾依曼設計的計算機架構也是以順序執行為基礎的。所以如果你總是不能把你的多線程程序搞定,恭喜你,你是個思維正常的程序猿:)

Python提供兩組線程的介面,一組是thread模塊,提供基礎的,低等級(Low Level)介面,使用Function作為線程的運行體。還有一組是threading模塊,提供更容易使用的基於對象的介面(類似於Java),可以繼承Thread對象來實現線程,還提供了其它一些線程相關的對象,例如Timer,Lock

使用thread模塊的例子
import thread

def worker():
"""thread worker function"""
print 'Worker'
thread.start_new_thread(worker)
使用threading模塊的例子
import threading
def worker():
"""thread worker function"""
print 'Worker'
t = threading.Thread(target=worker)
t.start()
或者Java Style
import threading

class worker(threading.Thread):
def __init__(self):
pass
def run():
"""thread worker function"""
print 'Worker'

t = worker()
t.start()

⑤ python是單線程的解釋語言,為何運行時多核cpu的佔用率會同時提升

(1) 在RTOS系統啟動前, 使用Tick中斷測試CPU的處理能力基準 CPUPerformanceBase;
(2) 在系統進入運行後, 使用空閑任務執行與測試CPU處理能力基準完全相同的演算法, 得到RTCPUPerformance.
(3) 周期地計算CPU佔用率, 並清除RTCPUPerformance的值, 一般每秒鍾計算一次:
RealTime CPU Load = 1 - (RTCPUPerformance/CPUPerformanceBase) * 100%

⑥ 怎麼讓python用多個cpu

python由於GIL的關系,python的多線程並沒有發揮多核的作用,這些線程都是在在單核上跑的所以要想發揮多核的作用,就需要使用多進程,盡可能的在每一個CPU核心上分配到一個python進程。所以要想跑滿多核CPU就得多進程多線程互相結合

⑦ python 多線程和多進程的區別 mutiprocessing theading

在socketserver服務端代碼中有這么一句:

server = socketserver.ThreadingTCPServer((ip,port), MyServer)

ThreadingTCPServer這個類是一個支持多線程和TCP協議的socketserver,它的繼承關系是這樣的:

class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass

右邊的TCPServer實際上是主要的功能父類,而左邊的ThreadingMixIn則是實現了多線程的類,ThreadingTCPServer自己本身則沒有任何代碼。

MixIn在Python的類命名中很常見,稱作「混入」,戲稱「亂入」,通常為了某種重要功能被子類繼承。

我們看看一下ThreadingMixIn的源代碼:

class ThreadingMixIn:

daemon_threads = False

def process_request_thread(self, request, client_address):
try:
self.finish_request(request, client_address)
self.shutdown_request(request)
except:
self.handle_error(request, client_address)
self.shutdown_request(request)

def process_request(self, request, client_address):

t = threading.Thread(target = self.process_request_thread,
args = (request, client_address))
t.daemon = self.daemon_threads
t.start()

在ThreadingMixIn類中,其實就定義了一個屬性,兩個方法。其中的process_request()方法實際調用的正是Python內置的多線程模塊threading。這個模塊是Python中所有多線程的基礎,socketserver本質上也是利用了這個模塊。

socketserver通過threading模塊,實現了多線程任務處理能力,可以同時為多個客戶提供服務。

那麼,什麼是線程,什麼是進程?

進程是程序(軟體,應用)的一個執行實例,每個運行中的程序,可以同時創建多個進程,但至少要有一個。每個進程都提供執行程序所需的所有資源,都有一個虛擬的地址空間、可執行的代碼、操作系統的介面、安全的上下文(記錄啟動該進程的用戶和許可權等等)、唯一的進程ID、環境變數、優先順序類、最小和最大的工作空間(內存空間)。進程可以包含線程,並且每個進程必須有至少一個線程。每個進程啟動時都會最先產生一個線程,即主線程,然後主線程會再創建其他的子線程。

線程,有時被稱為輕量級進程(Lightweight Process,LWP),是程序執行流的最小單元。一個標準的線程由線程ID,當前指令指針(PC),寄存器集合和堆棧組成。另外,線程是進程中的一個實體,是被系統獨立調度和分派的基本單位,線程自己不獨立擁有系統資源,但它可與同屬一個進程的其它線程共享該進程所擁有的全部資源。每一個應用程序都至少有一個進程和一個線程。在單個程序中同時運行多個線程完成不同的被劃分成一塊一塊的工作,稱為多線程。

舉個例子,某公司要生產一種產品,於是在生產基地建設了很多廠房,每個廠房內又有多條流水生產線。所有廠房配合將整個產品生產出來,單個廠房內的流水線負責生產所屬廠房的產品部件,每個廠房都擁有自己的材料庫,廠房內的生產線共享這些材料。公司要實現生產必須擁有至少一個廠房一條生產線。換成計算機的概念,那麼這家公司就是應用程序,廠房就是應用程序的進程,生產線就是某個進程的一個線程。

線程的特點:

線程是一個execution context(執行上下文),即一個cpu執行時所需要的一串指令。假設你正在讀一本書,沒有讀完,你想休息一下,但是你想在回來時繼續先前的進度。有一個方法就是記下頁數、行數與字數這三個數值,這些數值就是execution context。如果你的室友在你休息的時候,使用相同的方法讀這本書。你和她只需要這三個數字記下來就可以在交替的時間共同閱讀這本書了。

線程的工作方式與此類似。CPU會給你一個在同一時間能夠做多個運算的幻覺,實際上它在每個運算上只花了極少的時間,本質上CPU同一時刻只能幹一件事,所謂的多線程和並發處理只是假象。CPU能這樣做是因為它有每個任務的execution context,就像你能夠和你朋友共享同一本書一樣。

進程與線程區別:

  • 同一個進程中的線程共享同一內存空間,但進程之間的內存空間是獨立的。

  • 同一個進程中的所有線程的數據是共享的,但進程之間的數據是獨立的。

  • 對主線程的修改可能會影響其他線程的行為,但是父進程的修改(除了刪除以外)不會影響其他子進程。

  • 線程是一個上下文的執行指令,而進程則是與運算相關的一簇資源。

  • 同一個進程的線程之間可以直接通信,但是進程之間的交流需要藉助中間代理來實現。

  • 創建新的線程很容易,但是創建新的進程需要對父進程做一次復制。

  • 一個線程可以操作同一進程的其他線程,但是進程只能操作其子進程。

  • 線程啟動速度快,進程啟動速度慢(但是兩者運行速度沒有可比性)。

  • 由於現代cpu已經進入多核時代,並且主頻也相對以往大幅提升,多線程和多進程編程已經成為主流。Python全面支持多線程和多進程編程,同時還支持協程。

⑧ Python可以做大數據嗎

Python是數據科學家十分喜愛的編程語言,其內置了很多由C語言編寫的庫,操作起來更加方便,Python在網路爬蟲的傳統應用領域,在大數據的抓取方面具有先天優勢,目前,最流行的爬蟲框架Scrapy,HTTP工具包urlib2,HTML解析工具beautifulsoup,XML解析器lxml,等等,都是能夠獨當一面的Python類庫。

相關推薦:《Python基礎教程》

Python十分適合數據抓取工作,對於大數據的處理,具有一定的局限性:

Python在大數據處理方面的優勢:

1. 異常快捷的開發速度,代碼量少;

2. 豐富的數據處理包,使用十分方便;

3. 內部類型使用成本低;

4. 百萬級別數據可以採用Python處理。

Python在大數據處理方面的劣勢:

1. python線程有gil,多線程的時候只能在一個核上跑,浪費了多核伺服器;

2. python執行效率不高,在處理大數據的時候,效率不高;

3. 10億級別以上的數據Python效率低。

Python適合大數據的抓取、載入和分發,相比於其他語言更加簡單、高效;求一些常用的統計量和求一些基本演算法的結果,Python也有現成的高效的庫,但是針對大數據處理,Python具有一定的局限於,因此,涉及大數據處理時,可以用Python做整個流程的框架,核心CPU密集操作可以採用C語言等編程語言!

⑨ python的多線程是否能利用多核計算

比方我有一個4核的CPU,那麼這樣一來,在單位時間內每個核只能跑一個線程,然後時間片輪轉切換。但是Python不一樣,它不管你有幾個核,單位時間多個核只能跑一個線程,然後時間片輪轉。看起來很不可思議?但是這就是GIL搞的鬼。任何Python線程執行前,必須先獲得GIL鎖,然後,每執行100條位元組碼,解釋器就自動釋放GIL鎖,讓別的線程有機會執行。這個GIL全局鎖實際上把所有線程的執行代碼都給上了鎖,所以,多線程在Python中只能交替執行,即使100個線程跑在100核CPU上,也只能用到1個核。通常我們用的解釋器是官方實現的CPython,要真正利用多核,除非重寫一個不帶GIL的解釋器。

⑩ python如何利用多核cpu

Python,想利用多核CPU,那麼就應該進行處理,這樣才行的利用,所以一定要研究透徹

熱點內容
windows配置ftp 發布:2025-01-11 00:35:02 瀏覽:656
des演算法代碼c 發布:2025-01-11 00:33:42 瀏覽:805
共享文件夾設置密碼無法訪問 發布:2025-01-11 00:32:49 瀏覽:478
槽鋼演算法 發布:2025-01-11 00:26:21 瀏覽:883
linux命令包 發布:2025-01-10 23:54:26 瀏覽:32
python輪廓 發布:2025-01-10 23:49:23 瀏覽:178
思科配置線怎麼選 發布:2025-01-10 23:48:44 瀏覽:704
解壓水晶泥 發布:2025-01-10 23:27:23 瀏覽:634
小米攝像頭如何改wifi密碼 發布:2025-01-10 23:25:14 瀏覽:115
阿里雲伺服器首頁 發布:2025-01-10 23:24:15 瀏覽:436