亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Python并發(fā)編程多進(jìn)程,多線程及GIL全局解釋器鎖

 更新時間:2022年07月19日 08:54:10   作者:企鵝與蟒蛇  
這篇文章主要介紹了Python并發(fā)編程多進(jìn)程,多線程及GIL全局解釋器鎖,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的朋友可以參考一下

1. 并發(fā)與并行

  • 所謂的并行(Parallelism),就是多個彼此獨立的任務(wù)可以同時一起執(zhí)行,彼此并不相互干擾,并行強(qiáng)調(diào)的是同時且獨立的運(yùn)行,彼此不需要協(xié)作。
  • 而所謂并發(fā)(Concurrency),則是多個任務(wù)彼此交替執(zhí)行,但是同一時間只能有一個處于運(yùn)行狀態(tài),并發(fā)執(zhí)行強(qiáng)調(diào)任務(wù)之間的彼此協(xié)作。

并發(fā)通常被誤解為并行,并發(fā)實際是隱式的調(diào)度獨立的代碼,以協(xié)作的方式運(yùn)行。比如在等待IO線程完成IO操作之前,可以啟動IO線程之外的其他獨立代碼同步執(zhí)行其他操作。

關(guān)于并發(fā)、并行的圖示,如下:

由于CPython解釋器中的全局解釋器鎖(GIL,Global Interpreter Lock)的存在,所以Python中的并行實際上是一種假并行,并不是真正意義上的同時獨立運(yùn)行。

2. 線程與進(jìn)程的應(yīng)用場景

進(jìn)程(Process)是操作系統(tǒng)層面的一個抽象概念,它是運(yùn)行代碼創(chuàng)建出來的、加載到內(nèi)存中運(yùn)行的程序。電腦上通常運(yùn)行著多個進(jìn)程,這些進(jìn)程之間是彼此獨立運(yùn)行的。

線程(Thread)是操作系統(tǒng)可以調(diào)度的最小運(yùn)行程序單位,其包含在進(jìn)程中,一個進(jìn)程中通常至少包含1個線程,一些進(jìn)程中會包含多個線程。多個線程運(yùn)行的都是父進(jìn)程的相同代碼,理想情況下,這些線程是并行執(zhí)行的,但由于GIL的存在,所以它們實際上是交替執(zhí)行的,并不是真正意義上的獨立、并行的執(zhí)行的。

下表是進(jìn)程與線程的對比:

對于IO密集型的操作,更適合使用多線程編程的方式來解決問題;對于CPU密集型的操作,則更適合使用多進(jìn)程編程的方式來解決問題。

2.1. 并行/并發(fā)編程相關(guān)的技術(shù)棧

Python中提供了一些模塊用于實現(xiàn)并行/并發(fā)編程,具體如下所示:

threading:Python中進(jìn)行多線程編程的標(biāo)準(zhǔn)庫,是一個對_thread進(jìn)行再封裝的高級模塊。multiprocessing:類似于threading模塊,提供的API接口也與threading模塊類似,不同的是它進(jìn)行多進(jìn)程編程。concurrent.futures:標(biāo)準(zhǔn)庫中的一個模塊,在線程編程模塊的基礎(chǔ)上抽象出來的更高級實現(xiàn),且該模塊的編程為異步模式。queue:任務(wù)隊列模塊,queue中提供的隊列是線程安全的,所以可以使用這個模塊進(jìn)行線程之間進(jìn)行安全的數(shù)據(jù)交換操作。不支持分布式。celery:一個高級的分布式任務(wù)隊列,通過multiprocessing模塊或者gevent模塊可以實現(xiàn)隊列中人物的并發(fā)執(zhí)行。支持多節(jié)點之間的分布式計算。 2.2. 通過編碼比較多進(jìn)程與多線程的執(zhí)行效果

在下面的代碼中,定義了兩個函數(shù):only_sleep()以及crunch_numbers(),前者用于模擬IO密集型操作(需要頻繁中斷),后者用于模擬CPU密集型操作。

然后在串行調(diào)用、多線程的方式調(diào)用、多進(jìn)程的方式調(diào)用,三種不同的執(zhí)行環(huán)境中,比較各個函數(shù)的執(zhí)行效率情況。

具體代碼以及執(zhí)行結(jié)果如下所示:

import time
import datetime
import logging
import threading
import multiprocessing

FORMAT = "%(asctime)s [%(processName)s %(process)d] %(threadName)s %(thread)d <=%(message)s=>"
logging.basicConfig(format=FORMAT, level=logging.INFO, datefmt='%H:%M:%S')
def only_sleep():
	"""
	模擬IO阻塞型操作,此時多線程優(yōu)勢明顯

	:return:
	"""
	logging.info('in only_sleep function')
	time.sleep(1)
def crunch_numbers():
	"""
	模擬CPU密集型操作,此時多進(jìn)程優(yōu)勢明顯
	:return:
	"""
	logging.info('in crunch_numbers function')
	x = 0
	while x < 1000000:
    	x += 1
if __name__ == '__main__':
	work_repeat = 4
	print('==>> only_sleep function test')
	count = 0
	for func in (only_sleep, crunch_numbers):
    	count += 1
	    # run tasks serially
    	start1 = datetime.datetime.now()
	    for i in range(work_repeat):
    	    func()
	    stop1 = datetime.datetime.now()
    	delta1 = (stop1 - start1).total_seconds()
	    print('Serial Execution takes {} seconds~'.format(delta1))

    	# run tasks with multi-threads
	    start2 = datetime.datetime.now()
    	thread_lst = [threading.Thread(target=func, name='thread-worker' + str(i)) for i in range(work_repeat)]
	    [thd.start() for thd in thread_lst]
    	[thd.join() for thd in thread_lst]
	    stop2 = datetime.datetime.now()
    	delta2 = (stop2 - start2).total_seconds()
	    print('Multi-Threads takes {} seconds~'.format(delta2))
    	# run tasks with multiprocessing
	    start3 = datetime.datetime.now()
    	proc_lst = [multiprocessing.Process(target=func, name='process-worker' + str(i)) for i in range(work_repeat)]
	    [thd.start() for thd in proc_lst]
    	[thd.join() for thd in proc_lst]
	    stop3 = datetime.datetime.now()
    	delta3 = (stop3 - start3).total_seconds()
	    print('Multi-Processing takes {} seconds~'.format(delta3))
    	if count == 1:
        	print('\n', '*.' * 30, end='\n\n')
	        print('==>> crunch_numbers function test')

上述代碼的執(zhí)行結(jié)果如下:

23:55:51 [MainProcess 568124] MainThread 182168 <=in only_sleep function=>
==>> only_sleep function test
23:55:52 [MainProcess 568124] MainThread 182168 <=in only_sleep function=>
23:55:53 [MainProcess 568124] MainThread 182168 <=in only_sleep function=>
23:55:54 [MainProcess 568124] MainThread 182168 <=in only_sleep function=>
23:55:55 [MainProcess 568124] thread-worker0 553012 <=in only_sleep function=>
23:55:55 [MainProcess 568124] thread-worker1 567212 <=in only_sleep function=>
23:55:55 [MainProcess 568124] thread-worker2 547252 <=in only_sleep function=>
23:55:55 [MainProcess 568124] thread-worker3 561892 <=in only_sleep function=>
Serial Execution takes 4.022761 seconds~
Multi-Threads takes 1.01416 seconds~
23:55:56 [process-worker0 563068] MainThread 567480 <=in only_sleep function=>
23:55:56 [process-worker1 567080] MainThread 567628 <=in only_sleep function=>
23:55:56 [process-worker2 567868] MainThread 563656 <=in only_sleep function=>
23:55:56 [process-worker3 567444] MainThread 566436 <=in only_sleep function=>
23:55:57 [MainProcess 568124] MainThread 182168 <=in crunch_numbers function=>
Multi-Processing takes 1.11466 seconds~

*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.

==>> crunch_numbers function test
23:55:57 [MainProcess 568124] MainThread 182168 <=in crunch_numbers function=>
23:55:57 [MainProcess 568124] MainThread 182168 <=in crunch_numbers function=>
23:55:57 [MainProcess 568124] MainThread 182168 <=in crunch_numbers function=>
Serial Execution takes 0.1786 seconds~
23:55:57 [MainProcess 568124] thread-worker0 567412 <=in crunch_numbers function=>
23:55:57 [MainProcess 568124] thread-worker1 566468 <=in crunch_numbers function=>
23:55:57 [MainProcess 568124] thread-worker2 565272 <=in crunch_numbers function=>
23:55:57 [MainProcess 568124] thread-worker3 568044 <=in crunch_numbers function=>
Multi-Threads takes 0.195057 seconds~
23:55:58 [process-worker0 567652] MainThread 561892 <=in crunch_numbers function=>
23:55:58 [process-worker1 553012] MainThread 547252 <=in crunch_numbers function=>
23:55:58 [process-worker2 554024] MainThread 556500 <=in crunch_numbers function=>
23:55:58 [process-worker3 565004] MainThread 566108 <=in crunch_numbers function=>
Multi-Processing takes 0.155246 seconds~

Process finished with exit code 0

從上述執(zhí)行結(jié)果中可以看出:

上述代碼的執(zhí)行結(jié)果也驗證了此前的結(jié)論:對于IO密集型操作,適合使用多線程編程的方式解決問題;而對于CPU密集型的操作,則適合使用多進(jìn)程編程的方式解決問題。

3. Python中的GIL是什么,它影響什么

GIL是CPython中實現(xiàn)的全局解釋器鎖 (Global Interpreter Lock),由于CPython是使用最廣泛的Python解釋器,所以GIL也是Python世界中最飽受爭議的一個主題。

GIL是互斥鎖,其目的是為了確保線程安全,正是因為有了GIL,所以可以很方便的與外部非線程安全的模塊或者庫結(jié)合起來。但是這也是有代價的,由于有了GIL,所以導(dǎo)致Python中的并行并不是真正意義上的并行,所以也就無法同時創(chuàng)建兩個使用相同代碼段的線程,相同代碼的線程只能有一個處于執(zhí)行狀態(tài)。因為GIL互斥鎖,相同代碼訪問的數(shù)據(jù)會被加鎖,只有當(dāng)一個線程釋放鎖之后,相同代碼的另一個線程才能訪問未被加鎖的數(shù)據(jù)。

所以Python中的多線程是相互交替執(zhí)行的,并不是真正的并行執(zhí)行的。但是在CPython之外的一些庫,是可以實現(xiàn)真正意義上的并行的,比如numpy這個數(shù)據(jù)處理常用的庫。

到此這篇關(guān)于Python并發(fā)編程多進(jìn)程,多線程及GIL全局解釋器鎖的文章就介紹到這了,更多相關(guān)Python GIL解釋器鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python 數(shù)據(jù)結(jié)構(gòu)之隊列的實現(xiàn)

    Python 數(shù)據(jù)結(jié)構(gòu)之隊列的實現(xiàn)

    這篇文章主要介紹了Python 數(shù)據(jù)結(jié)構(gòu)之隊列的實現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • Python 爬蟲性能相關(guān)總結(jié)

    Python 爬蟲性能相關(guān)總結(jié)

    這篇文章主要介紹了Python 爬蟲性能的相關(guān)資料,文中講解非常詳細(xì),幫助大家更好的理解和學(xué)習(xí)爬蟲,感興趣的朋友可以了解下
    2020-08-08
  • 詳解利用Pandas求解兩個DataFrame的差集,交集,并集

    詳解利用Pandas求解兩個DataFrame的差集,交集,并集

    這篇文章主要和大家講解一下如何利用Pandas函數(shù)求解兩個DataFrame的差集、交集、并集,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2022-07-07
  • kafka-python 獲取topic lag值方式

    kafka-python 獲取topic lag值方式

    今天小編就為大家分享一篇kafka-python 獲取topic lag值方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • Python基于GDAL鑲嵌拼接遙感影像

    Python基于GDAL鑲嵌拼接遙感影像

    這篇文章主要介紹了Python基于GDAL鑲嵌拼接遙感影像, 這里有一點需要注意的就是,用這個方法進(jìn)行鑲嵌拼接操作時,影像有一條明顯的拼接線,不知道是不是我數(shù)據(jù)的問題,你們可以自己嘗試一下,只要修改主函數(shù)中的路徑即可,需要的朋友可以參考下
    2023-10-10
  • python爬蟲爬取監(jiān)控教務(wù)系統(tǒng)的思路詳解

    python爬蟲爬取監(jiān)控教務(wù)系統(tǒng)的思路詳解

    這篇文章主要介紹了python爬蟲監(jiān)控教務(wù)系統(tǒng),主要實現(xiàn)思路是對已有的成績進(jìn)行處理,變?yōu)閘ist集合,本文通過實例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2020-01-01
  • Python判斷變量是否為Json格式的字符串示例

    Python判斷變量是否為Json格式的字符串示例

    這篇文章主要給大家介紹了利用Python判斷變量是否為Json格式的字符串的相關(guān)資料,文中給出了詳細(xì)的示例代碼供大家參考學(xué)習(xí),需要的朋友們下面來一起看看吧。
    2017-05-05
  • Python實現(xiàn)處理圖片水印的方法詳解

    Python實現(xiàn)處理圖片水印的方法詳解

    這篇文章主要為大家詳細(xì)介紹了如何利用Python實現(xiàn)處理圖片水印的相關(guān)資料,主要是實現(xiàn)圖片水印的去除效果,感興趣的小伙伴可以嘗試一下
    2022-11-11
  • Python函數(shù)的周期性執(zhí)行實現(xiàn)方法

    Python函數(shù)的周期性執(zhí)行實現(xiàn)方法

    這篇文章主要介紹了Python函數(shù)的周期性執(zhí)行實現(xiàn)方法,涉及Python使用sched模塊實現(xiàn)函數(shù)周期性調(diào)度觸發(fā)的相關(guān)技巧,需要的朋友可以參考下
    2016-08-08
  • 關(guān)于Python?Selenium自動化導(dǎo)出新版WOS(web?of?science)檢索結(jié)果的問題

    關(guān)于Python?Selenium自動化導(dǎo)出新版WOS(web?of?science)檢索結(jié)果的問題

    這篇文章主要介紹了Python?Selenium自動化導(dǎo)出新版WOS(web?of?science)檢索結(jié)果,本代碼屬于半自動化導(dǎo)出,考慮到開發(fā)效率等因素,有兩處在首次導(dǎo)出時需要手動操作,具體實現(xiàn)過程跟隨小編一起看看吧
    2022-01-01

最新評論