您好,登錄后才能下訂單哦!
Python中多處理與多線程的區(qū)別是什么,相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。
什么是線程?你為什么想要它?
Python是一種線性語言。但是,當您需要更多的處理能力時,線程模塊就派上用場了。
Python中的線程不能用于并行CPU計算。但是它非常適合于I/O操作,比如web抓取,因為處理器處于空閑狀態(tài),等待數(shù)據(jù)。
線程化改變了游戲規(guī)則,因為許多與網(wǎng)絡(luò)/數(shù)據(jù) I/O相關(guān)的腳本將大部分時間花費在等待來自遠程數(shù)據(jù)源上。有時候,下載可能沒有鏈接(例如,如果您正在抓取不同的網(wǎng)站),處理器可以并行地從不同的數(shù)據(jù)源下載并在最后合并結(jié)果。
線程包含在標準庫中:
import threading from queue import Queue import time
您可以使用target作為可調(diào)用的對象,args將參數(shù)傳遞給函數(shù),并開始啟動線程:
def testThread(num): print num if __name__ == '__main__': for i in range(5): t = threading.Thread(target=testThread, arg=(i,)) t.start()
鎖(lock)
您通常希望您的線程能夠使用或修改線程之間的公共變量。要做到這一點,你必須使用一種叫做鎖(lock)的東西。
每當一個函數(shù)想要修改一個變量時,它就會鎖定該變量。當另一個函數(shù)想要使用一個變量時,它必須等待,直到該變量被解鎖。
假設(shè)有兩個函數(shù)都對一個變量進行了1次迭代。鎖允許您確保一個函數(shù)可以訪問變量、執(zhí)行計算并在另一個函數(shù)訪問相同的變量之前寫回該變量。
您可以使用打印鎖來確保一次只能打印一個線程。這可以防止文本在打印時變得混亂(并導致數(shù)據(jù)損壞)。
在下面的代碼中,我們有10個我們想要完成的工作和5個將要工作的工人:
print_lock = threading.Lock() def threadTest(): # when this exits, the print_lock is released with print_lock: print(worker) def threader(): while True: # get the job from the front of the queue threadTest(q.get()) q.task_done() q = Queue() for x in range(5): thread = threading.Thread(target = threader) # this ensures the thread will die when the main thread dies # can set t.daemon to False if you want it to keep running t.daemon = True t.start() for job in range(10): q.put(job)
多線程并不總是完美的解決方案
我們發(fā)現(xiàn)許多教程都傾向于忽略使用他們剛教過你的工具的缺點。理解使用所有這些工具的利弊是很重要的。
例如:
管理線程需要時間,因此它適用于基本任務(wù)(如示例)
線程化增加了程序的復雜性,從而增加了調(diào)試的難度
多處理是什么?它與線程有什么不同?
在沒有多處理(multiprocessing)的情況下,由于GIL(全局解釋器鎖 Global Interpreter Lock),Python程序很難最大化系統(tǒng)的規(guī)格。Python的設(shè)計并沒有考慮到個人計算機可能有多個核心。因此GIL是必要的,因為Python不是線程安全的,而且在訪問Python對象時存在一個全局強制鎖。雖然不完美,但它是一種非常有效的內(nèi)存管理機制。
多處理允許您創(chuàng)建可以并發(fā)運行的程序(繞過GIL)并使用整個CPU內(nèi)核。盡管它與線程庫有本質(zhì)的不同,但是語法非常相似。多處理庫為每個進程提供了自己的Python解釋器,以及各自的GIL。
因此,與線程相關(guān)的常見問題(如數(shù)據(jù)損壞和死鎖)不再是問題。因為進程不共享內(nèi)存,所以它們不能并發(fā)地修改相同的內(nèi)存。
讓我們開始代碼演示:
import multiprocessing def spawn(): print('test!') if __name__ == '__main__': for i in range(5): p = multiprocessing.Process(target=spawn) p.start()
如果您有一個共享數(shù)據(jù)庫,您希望確保在啟動新數(shù)據(jù)庫之前,正在等待相關(guān)進程完成。
for i in range(5): p = multiprocessing.Process(target=spawn) p.start() p.join() # this line allows you to wait for processes
如果希望將參數(shù)傳遞給進程,可以使用args實現(xiàn)這一點:
import multiprocessing def spawn(num): print(num) if __name__ == '__main__': for i in range(25): ## right here p = multiprocessing.Process(target=spawn, args=(i,)) p.start()
這是一個簡單的例子,因為正如您所注意到的,數(shù)字的排列順序與您所期望的不一致(沒有p.join())。
與線程一樣,多處理仍然有缺點……你必須選擇其中一個壞處:
在進程之間轉(zhuǎn)移數(shù)據(jù)會帶來I/O開銷
整個內(nèi)存被復制到每個子進程中,對于更重要的程序來說,這會帶來很大的開銷
看完上述內(nèi)容,你們掌握Python中多處理與多線程的區(qū)別是什么的方法了嗎?如果還想學到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。