日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

10月13日学习内容整理:线程,创建线程(threading模块),守护线程,GIL(全局解释器互斥锁)...

發(fā)布時間:2023/12/15 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 10月13日学习内容整理:线程,创建线程(threading模块),守护线程,GIL(全局解释器互斥锁)... 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、線程

1、概念:一條流水線的工作過程

2、和進程的區(qū)別和關(guān)系

(1)關(guān)系

》進程是資源單位,線程是執(zhí)行單位,cpu真正執(zhí)行的是線程

》一個進程至少有一個線程

》多線程針對的是一個進程的概念

》從執(zhí)行的角度說:執(zhí)行一個進程就相當于開啟一個控制(主)線程

》從資源的角度說:開啟一個進程就是開辟一個內(nèi)存空間

(2)區(qū)別

》核心1:創(chuàng)建線程開銷很小,不用申請空間(比進程快10-100倍);而進程開銷大需要申請空間

》核心2:同一進程的多個線程共享該進程的資源和地址空間;但是不同進程的地址空間是隔離的

》線程可以直接訪問進程的數(shù)據(jù);而子進程是會拷貝父進程的所有數(shù)據(jù)

》同一進程的多個線程之間可以直接通信;而不同的進程通信則要依靠IPC機制

》線程可以控制同一進程的其它線程;進程只能控制它的子進程

》改變主線程可能貴影響其它線程的行為;改變父進程不會影響子進程

3、和進程的對比

》線程沒有“父子”概念

》同一進程的不同線程的進程ID都是一樣的

》由于線程共享進程的資源,所以當線程對數(shù)據(jù)修改時修改的就是該進程內(nèi)存空間中的數(shù)據(jù),但要注意線程和控制線程(該進程)對數(shù)據(jù)處理的時間先后順序

?

二、創(chuàng)建線程

1、代碼實現(xiàn):Thread類(threading模塊)

t = Thread(target=函數(shù)名,args=(參數(shù),)/kwargs={字典}) ? 實例化

t.start() ? 發(fā)送創(chuàng)建線程請求(由于創(chuàng)建線程開銷很小,所以發(fā)送請求的同時基本就開啟了線程)

t .join() ? ? 主線程等待線程結(jié)束

from threading import Thread from multiprocessing import Processdef work(n):print('%s is running' %n)if __name__ == '__main__':t=Thread(target=work,args=(1,))t.start()print('主線程')

?

2、其它方法:

(1)對象方法

》isAlive() 線程是否存活

》getName() ?獲取當前線程的名字,默認Thread-1,Thread-2,...這樣

》setName() ? 設(shè)置當前線程的名字

(2)模塊提供的方法

》currentThread() 獲取當前線程對象

》enumerate() 顯示當前活躍線程,輸出列表

》activeCount() ?當前活躍線程的數(shù)目

?

三、守護線程

1、代碼實現(xiàn):

t.daemon=True ? ?必須在start()之前設(shè)置

2、概念

》當控制線程(從執(zhí)行角度上看是該進程)結(jié)束守護線程也隨之結(jié)束

》控制線程只有當所有非守護線程都結(jié)束時才算結(jié)束

from threading import Thread import time def foo():print(123)time.sleep(5)print("end123")def bar():print(456)time.sleep(3)print("end456")if __name__ == '__main__':t1=Thread(target=foo)t2=Thread(target=bar)t1.daemon=Truet1.start()t2.start()print("main-------")

?

四、GIL:全局解釋器互斥鎖(不是python的特性)

1、產(chǎn)生背景:在Cpython解釋器中特有的,因為python解釋器帶有數(shù)據(jù)回收機制,這樣就會帶來回收和利用的沖突性,所以就要求一個進程的多個線程同一時間只能有一個被執(zhí)行

2、本質(zhì):就是一把互斥鎖,實現(xiàn)將并發(fā)變?yōu)榇?#xff0c;保證數(shù)據(jù)安全

》》》#1 所有數(shù)據(jù)都是共享的,這其中,代碼作為一種數(shù)據(jù)也是被所有線程共享的(test.py的所有代碼以及Cpython解釋器的所有代碼)
》》》例如:test.py定義一個函數(shù)work,在進程內(nèi)所有線程都能訪問到work的代碼,于是我們可以開啟三個線程然后target都指向該代碼,能訪問到意味著就是可以執(zhí)行。

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

?

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

?

3、實現(xiàn)方式:

with ?lock:

    python解釋器的代碼()

這個lock就是GIL

?

?

4、GIL和lock:

》要根據(jù)不同的數(shù)據(jù)來加不同的鎖,因為GIL保證不了用戶數(shù)據(jù)的安全,GIL只能保護python解釋器級別的數(shù)據(jù)

》線程要想被執(zhí)行就要去搶GIL鎖(也就是爭執(zhí)行權(quán)限)

?

5、GIL和多線程

》對于多個計算密集型的程序

(1)單核情況下:因為始終只有一個cpu去執(zhí)行計算,所以就要求開銷要小,故選擇多線程

(2)多核情況下:因為有多個cpu去執(zhí)行計算,能夠?qū)崿F(xiàn)真正的并行,效率會很高,而線程每次只有一個在執(zhí)行沒有利用多核的優(yōu)勢,故選擇多進程

》對于多個IO密集型程序

(1)單核情況下:因為只有一個cpu執(zhí)行,需要不斷的切換來實現(xiàn)并發(fā),所以要求開銷盡量要小,故選擇多線程

(2)多核情況下:多個cpu執(zhí)行的話,遇到IO仍然要阻塞,若是多進程的話就會常常是阻塞狀態(tài),運行時間就會是時間最長的哪個程序,而如果是多線程,首先開銷很小,其次每次執(zhí)行一個線程遇到IO阻塞就會立即去處理別的線程,這樣效率會提高,故選擇多線程

?

6、為什么要有GIL和代碼運行的整個過程

》首先,python解釋器帶有的數(shù)據(jù)回收機制,本身是有計數(shù)器的,通過計數(shù)來判斷是否為垃圾數(shù)據(jù),而這個計數(shù)就是python解釋器中的代碼提供的功能(其實也是一段程序來實現(xiàn))也就是python解釋器級別的數(shù)據(jù),而肯定有可能會出現(xiàn)當python解釋器要回收某一個數(shù)據(jù)而某一個程序正好要使用這個數(shù)據(jù)的情況,這就帶來了沖突,為了解決這種沖突保護數(shù)據(jù)安全就必須保證同一時間內(nèi)只能有一個程序來使用python解釋器的代碼,這就變成了串行,所以就引入了GIL鎖的應(yīng)用

》我們寫一段python代碼,首先肯定要打開python解釋器,這就相當于開啟了一個代碼解釋器的進程,我們在解釋器中寫代碼其實就是用了解釋器的功能(也就是通過一段程序?qū)崿F(xiàn)的功能),而代碼本身是不會自己運行的,運行我們所寫的代碼其實就是開啟了另一個進程(即是python解釋器進程的子進程)也就是將我們所寫的代碼作為參數(shù)傳給python解釋器來執(zhí)行(這其實就是相當于子進程創(chuàng)建時會把父進程(python解釋器的代碼)的所有數(shù)據(jù)都拷貝,這樣子進程(我們所寫的代碼)才能運行),而由于GIL鎖的存在,每個程序要想運行就要去搶這把鎖也就是爭取運行權(quán)限,爭到了就執(zhí)行若遇到阻塞操作系統(tǒng)就會強制釋放掉該程序的運行權(quán)限(也就是釋放掉GIL鎖),這樣別的程序再去搶然后運行,等之前的程序處于就緒態(tài)時會再去搶GIL鎖接著之前的運行狀態(tài)繼續(xù)執(zhí)行,這就是一段代碼要想運行起來必須經(jīng)歷的過程

補充一下:

1、開啟python解釋器操作系統(tǒng)其實是將解釋器的代碼從硬盤中取出放到內(nèi)存中去運行,我們所寫的代碼也是這樣的

2、其實進程和線程的創(chuàng)建和開啟(個數(shù)快慢等,當然線程的開銷肯定要比進程小很多),包括程序運行時對GIL鎖的爭搶和釋放以及運行狀態(tài)的保留等,這些都是由操作系統(tǒng)及電腦性能來控制和決定的,無法由程序本身來操控

》上面說到每個程序運行前要搶GIL鎖(運行權(quán)限),運行起來時就是按照自己的代碼來運行,會產(chǎn)生自己的數(shù)據(jù),而這個數(shù)據(jù)GIL是保護不了的,因為GIL只是鎖住了解釋器而沒有鎖住每個進程對同一塊數(shù)據(jù)的處理功能,所以這就是為什么不同的數(shù)據(jù)要加不同的鎖來保護,GIL只是保護python解釋器代碼級別的數(shù)據(jù)而已

?

轉(zhuǎn)載于:https://www.cnblogs.com/wanghl1011/articles/7663035.html

總結(jié)

以上是生活随笔為你收集整理的10月13日学习内容整理:线程,创建线程(threading模块),守护线程,GIL(全局解释器互斥锁)...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。