国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Python解析器Cpython的GIL解釋器鎖工作機制

89542767 / 421人閱讀

  小編寫這篇文章的一個主要目的,主要是來給大家做個解答,解答的內容主要是涉及到的內容有Python解析器的一些相關介紹,介紹的內容主要是Cpython的GIL解釋器解鎖相關機制的一些介紹。具體的內容,下面就給大家詳細解答下。


  本節重點


  掌握Cpython的GIL解釋器鎖的工作機制


  掌握GIL與互斥鎖


  掌握Cpython下多線程與多進程各自的應用場景


  本節時長需控制在45分鐘內


  一引子


  定義:


  In CPython,the global interpreter lock,or GIL,is a mutex that prevents multiple


  native threads from executing Python bytecodes at once.This lock is necessary mainly


  because CPython’s memory management is not thread-safe.(However,since the GIL


  exists,other features have grown to depend on the guarantees that it enforces.)


  結論:在Cpython解釋器中,同一個進程下開啟的多線程,同一時刻只能有一個線程執行,無法利用多核優勢


  首先需要明確的一點是GIL并不是Python的特性,它是在實現Python解析器(CPython)時所引入的一個概念。就好比C++是一套語言(語法)標準,但是可以用不同的編譯器來編譯成可執行代碼。


  有名的編譯器例如GCC,INTEL C++,Visual C++等。Python也一樣,同樣一段代碼可以通過CPython,PyPy,Psyco等不同的Python執行環境來執行。


  像其中的JPython就沒有GIL。然而因為CPython是大部分環境下默認的Python執行環境。


  所以在很多人的概念里CPython就是Python,也就想當然的把GIL歸結為Python語言的缺陷。


  所以這里要先明確一點:GIL并不是Python的特性,Python完全可以不依賴于GIL


  二GIL介紹


  GIL本質就是一把互斥鎖,既然是互斥鎖,所有互斥鎖的本質都一樣,都是將并發運行變成串行,以此來控制同一時間內共享數據只能被一個任務所修改,進而保證數據安全。


  可以肯定的一點是:保護不同的數據的安全,就應該加不同的鎖。


  要想了解GIL,首先確定一點:每次執行python程序,都會產生一個獨立的進程。例如python test.py,python aaa.py,python bbb.py會產生3個不同的python進程


  驗證python test.py只會產生一個進程


  #test.py內容
  import os,time
  print(os.getpid())
  time.sleep(1000)
  #打開終端執行
  python3 test.py
  #在windows下查看
  tasklist|findstr python


  #在linux下下查看


  ps aux|grep python


  在一個python的進程內,不僅有test.py的主線程或者由該主線程開啟的其他線程,還有解釋器開啟的垃圾回收等解釋器級別的線程,總之,所有線程都運行在這一個進程內,毫無疑問


  1、所有數據都是共享的,這其中,代碼作為一種數據也是被所有線程共享的(test.py的所有代碼以及Cpython解釋器的所有代碼)


  例如:test.py定義一個函數work(代碼內容如下圖),在進程內所有線程都能訪問到work的代碼,于是我們可以開啟三個線程然后target都指向該代碼,能訪問到意味著就是可以執行。


  2、所有線程的任務,都需要將任務的代碼當做參數傳給解釋器的代碼去執行,即所有的線程要想運行自己的任務,首先需要解決的是能夠訪問到解釋器的代碼。


  綜上:


  如果多個線程的target=work,那么執行流程是


  多個線程先訪問到解釋器的代碼,即拿到執行權限,然后將target的代碼交給解釋器的代碼去執行


  解釋器的代碼是所有線程共享的,所以垃圾回收線程也可能訪問到解釋器的代碼而去執行,這就導致了一個問題:對于同一個數據100,可能線程1執行x=100的同時,而垃圾回收執行的是回收100的操作,解決這種問題沒有什么高明的方法,就是加鎖處理,如下圖的GIL,保證python解釋器同一時間只能執行一個任務的代碼

01.png

  三GIL與Lock


  機智的同學可能會問到這個問題:Python已經有一個GIL來保證同一時間只能有一個線程來執行了,為什么這里還需要lock?


  首先,我們需要達成共識:鎖的目的是為了保護共享的數據,同一時間只能有一個線程來修改共享的數據


  然后,我們可以得出結論:保護不同的數據就應該加不同的鎖。


  最后,問題就很明朗了,GIL與Lock是兩把鎖,保護的數據不一樣,前者是解釋器級別的(當然保護的就是解釋器級別的數據,比如垃圾回收的數據),后者是保護用戶自己開發的應用程序的數據,很明顯GIL不負責這件事,只能用戶自定義加鎖處理,即Lock,如下圖

02.png

  分析:


  1、100個線程去搶GIL鎖,即搶執行權限


  2、肯定有一個線程先搶到GIL(暫且稱為線程1),然后開始執行,一旦執行就會拿到lock.acquire()


  3、極有可能線程1還未運行完畢,就有另外一個線程2搶到GIL,然后開始運行,但線程2發現互斥鎖lock還未被線程1釋放,于是阻塞,被迫交出執行權限,即釋放GIL


  4、直到線程1重新搶到GIL,開始從上次暫停的位置繼續執行,直到正常釋放互斥鎖lock,然后其他的線程再重復2 3 4的過程


  代碼示范


  from threading import Thread,Lock
  import os,time
  def work():
  global n
  lock.acquire()
  temp=n
  time.sleep(0.1)
  n=temp-1
  lock.release()
  if __name__=='__main__':
  lock=Lock()
  n=100
  l=[]
  for i in range(100):
  p=Thread(target=work)
  l.append(p)
  p.start()
  for p in l:
  p.join()
  print(n)#結果肯定為0,由原來的并發執行變成串行,犧牲了執行效率保證了數據安全,不加鎖則結果可能為99


  四GIL與多線程


  有了GIL的存在,同一時刻同一進程中只有一個線程被執行


  聽到這里,有的同學立馬質問:進程可以利用多核,但是開銷大,而python的多線程開銷小,但卻無法利用多核優勢,也就是說python沒用了,php才是最牛逼的語言?


  別著急啊,老娘還沒講完呢。


  要解決這個問題,我們需要在幾個點上達成一致:


  1、cpu到底是用來做計算的,還是用來做I/O的?


  2、多cpu,意味著可以有多個核并行完成計算,所以多核提升的是計算性能


  3、每個cpu一旦遇到I/O阻塞,仍然需要等待,所以多核對I/O操作沒什么用處


  一個工人相當于cpu,此時計算相當于工人在干活,I/O阻塞相當于為工人干活提供所需原材料的過程,工人干活的過程中如果沒有原材料了,則工人干活的過程需要停止,直到等待原材料的到來。


  如果你的工廠干的大多數任務都要有準備原材料的過程(I/O密集型),那么你有再多的工人,意義也不大,還不如一個人,在等材料的過程中讓工人去干別的活,


  反過來講,如果你的工廠原材料都齊全,那當然是工人越多,效率越高


  結論:


  1、對計算來說,cpu越多越好,但是對于I/O來說,再多的cpu也沒用


  2、當然對運行一個程序來說,隨著cpu的增多執行效率肯定會有所提高(不管提高幅度多大,總會有所提高),這是因為一個程序基本上不會是純計算或者純I/O,所以我們只能相對的去看一個程序到底是計算密集型還是I/O密集型,從而進一步分析python的多線程到底有無用武之地


  假設我們有四個任務需要處理,處理方式肯定是要玩出并發的效果,解決方案可以是:


  方案一:開啟四個進程


  方案二:一個進程下,開啟四個線程


  單核情況下,分析結果:


  如果四個任務是計算密集型,沒有多核來并行計算,方案一徒增了創建進程的開銷,方案二勝


  如果四個任務是I/O密集型,方案一創建進程的開銷大,且進程的切換速度遠不如線程,方案二勝


  多核情況下,分析結果:


  如果四個任務是計算密集型,多核意味著并行計算,在python中一個進程中同一時刻只有一個線程執行用不上多核,方案一勝


  如果四個任務是I/O密集型,再多的核也解決不了I/O問題,方案二勝


  結論:


  現在的計算機基本上都是多核,python對于計算密集型的任務開多線程的效率并不能帶來多大性能上的提升,甚至不如串行(沒有大量切換),但是,對于IO密集型的任務效率還是有顯著提升的。


  五多線程性能測試


  如果并發的多個任務是計算密集型:多進程效率高


  from multiprocessing import Process
  from threading import Thread
  import os,time
  def work():
  res=0
  for i in range(100000000):
  res*=i
  if __name__=='__main__':
  l=[]
  print(os.cpu_count())#本機為4核
  start=time.time()
  for i in range(4):
  p=Process(target=work)#耗時5s多
  p=Thread(target=work)#耗時18s多
  l.append(p)
  p.start()
  for p in l:
  p.join()
  stop=time.time()
  print('run time is%s'%(stop-start))
  如果并發的多個任務是I/O密集型:多線程效率高
  from multiprocessing import Process
  from threading import Thread
  import threading
  import os,time
  def work():
  time.sleep(2)
  print('===>')
  if __name__=='__main__':
  l=[]
  print(os.cpu_count())#本機為4核
  start=time.time()
  for i in range(400):
  #p=Process(target=work)#耗時12s多,大部分時間耗費在創建進程上
  p=Thread(target=work)#耗時2s多
  l.append(p)
  p.start()
  for p in l:
  p.join()
  stop=time.time()
  print('run time is%s'%(stop-start))


  應用:


  多線程用于IO密集型,如socket,爬蟲,web


  多進程用于計算密集型,如金融分析


  綜上所述,上述內容就給大家介紹完畢,希望可以給大家帶來一定的幫助。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/128440.html

相關文章

  • 淺談Python多線程

    摘要:進程可創建多個線程來執行同一程序的不同部分。就緒等待線程調度。運行線程正常運行阻塞暫停運行,解除阻塞后進入狀態重新等待調度。消亡線程方法執行完畢返回或者異常終止。多線程多的情況下,依次執行各線程的方法,前頭一個結束了才能執行后面一個。 淺談Python多線程 作者簡介: 姓名:黃志成(小黃)博客: 博客 線程 一.什么是線程? 操作系統原理相關的書,基本都會提到一句很經典的話: 進程...

    zsirfs 評論0 收藏0
  • python多線程、、event事件機制簡單使用

    摘要:從調用方法啟動線程,到方法執行完畢或遇到未處理異常而中斷這段時間內,線程是激活的調用將會使主調線程堵塞,直到被調用線程運行結束或超時。對象實現了簡單的線程通信機制,它提供了設置信號,清除信號,等待等用于實現線程間的通信。 線程和進程 1、線程共享創建它的進程的地址空間,進程有自己的地址空間2、線程可以訪問進程所有的數據,線程可以相互訪問 3、線程之間的數據是獨立的 4、子進程復制線程的...

    lowett 評論0 收藏0
  • 從偽并行 Python 多線程說起

    摘要:多個線程可以同時執行。現在我們執行,嘗試在不同數量的線程中執行這個函數。如果線程是真并行,時間開銷應該不會隨線程數大幅上漲。由此可見,確實是造成偽并行現象的主要因素。小結由于的存在,大多數情況下多線程無法利用多核優勢。 本文首發于本人博客,轉載請注明出處 寫在前面 作者電腦有 4 個 CPU,因此使用 4 個線程測試是合理的 本文使用的 cpython 版本為 3.6.4 本文使...

    SegmentFault 評論0 收藏0
  • GIL 已經被殺死了么?

    摘要:酷睿代在年取代了奔騰,主頻遠低于此。該詞被敏捷開發團隊使用較多,含義與形式會略有不同,更改已經開始將垃圾收集器的狀態轉到解釋器,因此每個子解釋器將擁有它自己的本該如此。結論死亡了嗎對于單線程的應用程序,仍然存活。showImg(https://user-gold-cdn.xitu.io/2019/5/19/16ad09f554fdf443); 本文原創并首發于公眾號【Python貓】,未經授...

    番茄西紅柿 評論0 收藏0
  • GIL 已經被殺死了么?

    摘要:酷睿代在年取代了奔騰,主頻遠低于此。該詞被敏捷開發團隊使用較多,含義與形式會略有不同,更改已經開始將垃圾收集器的狀態轉到解釋器,因此每個子解釋器將擁有它自己的本該如此。結論死亡了嗎對于單線程的應用程序,仍然存活。showImg(https://user-gold-cdn.xitu.io/2019/5/19/16ad09f554fdf443); 本文原創并首發于公眾號【Python貓】,未經授...

    pkwenda 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<