計算機(jī)有5大基本組成部分,運(yùn)算器,控制器,存儲器,輸入和輸出。運(yùn)算器和控制器封裝到一起,加上寄存器組和cpu內(nèi)部總線構(gòu)成中央處理器(CPU)。cpu的根本任務(wù),就是執(zhí)行指令,對計算機(jī)來說,都是0,1組成的序列,cpu從邏輯上可以劃分為3個模塊:控制單元、運(yùn)算單元和存儲單元。這三個部分由cpu總線連接起來。
創(chuàng)新互聯(lián)公司專注于網(wǎng)站建設(shè)|成都網(wǎng)站維護(hù)|優(yōu)化|托管以及網(wǎng)絡(luò)推廣,積累了大量的網(wǎng)站設(shè)計與制作經(jīng)驗(yàn),為許多企業(yè)提供了網(wǎng)站定制設(shè)計服務(wù),案例作品覆蓋成都混凝土攪拌站等行業(yè)。能根據(jù)企業(yè)所處的行業(yè)與銷售的產(chǎn)品,結(jié)合品牌形象的塑造,量身制作品質(zhì)網(wǎng)站。
CPU的運(yùn)行原理就是:控制單元在時序脈沖的作用下,將指令計數(shù)器里所指向的指令地址(這個地址是在內(nèi)存里的)送到地址總線上去,然后CPU將這個地址里的指令讀到指令寄存器進(jìn)行譯碼。對于執(zhí)行指令過程中所需要用到的數(shù)據(jù),會將數(shù)據(jù)地址也送到地址總線,然后CPU把數(shù)據(jù)讀到CPU的內(nèi)部存儲單元(就是內(nèi)部寄存器)暫存起來,最后命令運(yùn)算單元對數(shù)據(jù)進(jìn)行處理加工。周而復(fù)始,一直這樣執(zhí)行下去。
并發(fā):并發(fā)當(dāng)有多個線程在操作時,如果系統(tǒng)只有一個CPU,則它根本不可能真正同時進(jìn)行一個以上的線程,它只能把CPU運(yùn)行時間劃分成若干個時間段,再將時間 段分配給各個線程執(zhí)行,在一個時間段的線程代碼運(yùn)行時,其它線程處于掛起狀。.這種方式我們稱之為并發(fā)(Concurrent)。
并行:當(dāng)系統(tǒng)有一個以上CPU時,則線程的操作有可能非并發(fā)。當(dāng)一個CPU執(zhí)行一個線程時,另一個CPU可以執(zhí)行另一個線程,兩個線程互不搶占CPU資源,可以同時進(jìn)行,這種方式我們稱之為并行(Parallel)。
并發(fā)與并行的區(qū)別:
多進(jìn)程是各個并行任務(wù)之間“不使用“共同的內(nèi)存空間;而多線程的各個并行任務(wù)”使用“共同的內(nèi)存空間。
(1)多進(jìn)程Python 全局解釋器鎖或GIL,簡單來說,是一個互斥鎖(或鎖),它只允許一個線程控制 Python 解釋器。這意味著在任何時間點(diǎn)都只能有一個線程處于執(zhí)行狀態(tài)。執(zhí)行單線程程序的開發(fā)人員看不到 GIL 的影響,但它可能是 CPU 密集型和多線程代碼中的性能瓶頸。由于即使在具有多個 CPU 內(nèi)核的多線程架構(gòu)中,GIL 也只允許一次執(zhí)行一個線程,因此 GIL 被稱為 Python 的“臭名昭著”的特性,但是它確實(shí)為Python內(nèi)存處理提供了方便。
如果一個對象同時被多個線程來引用,那么引用計數(shù)可能同時增加或減少,每個線程按照自己的方式進(jìn)行計數(shù),對象在整個內(nèi)存中的引用變得十分混亂,很容易造成內(nèi)存泄漏或者其他很多不可預(yù)見的Bug。一個解決辦法給就是每個線程都給引用計數(shù)加一個鎖,阻止別人修改,不過這樣會造成鎖死現(xiàn)象(比如一個對象有多個鎖時),另外,大量的資源會浪費(fèi)在加鎖解鎖的過程了,嚴(yán)重拖慢了程序運(yùn)行速度。
這個時候,就需要一個統(tǒng)一來管理引用計數(shù)的機(jī)制,以確保對象引用計數(shù)準(zhǔn)確、安全。全局解釋器鎖就是用來處理這種情況的。它既避免了不同線程帶來的引用計數(shù)混亂,又避免了過多線程鎖帶來的死鎖和運(yùn)行效率低的問題。雖然全局解釋器鎖解決了對象引用計數(shù)的問題,但隨之而來的是,很多CPU密集型任務(wù)在全局解釋器鎖的作用下,實(shí)際上變成了單線程,不能充分發(fā)揮CPU的算力,影響程序速度。
全局解釋器鎖并不是Python獨(dú)有的,其他一些語言,比如Ruby也存在全局解釋器鎖。還有一些語言沒有使用引用計數(shù)的方式來管理內(nèi)容,而是使用垃圾回收機(jī)制(GC)來管理內(nèi)存。雖然這樣避免了全局解釋器鎖,但是在單線程處理上,GC并不占有優(yōu)勢。
全局解釋器鎖對多線程的影響
進(jìn)程就是運(yùn)行著的程序。寫的python程序(或者其他應(yīng)用程序比如畫筆、qq等),運(yùn)行起來,就稱之為一個進(jìn)程;在windows下面打開任務(wù)管理器,里面顯示了當(dāng)前系統(tǒng)上運(yùn)行著的進(jìn)程。這些程序還沒有運(yùn)行的時候,它們的程序代碼文件存儲在磁盤中,就是那些擴(kuò)展名為 .exe 文件。雙擊它們,這些 .exe 文件就被os加載到內(nèi)存中,運(yùn)行起來,成為進(jìn)程。
進(jìn)程池:可以提供指定數(shù)量的進(jìn)程給用戶使用,即當(dāng)有新的請求提交到進(jìn)程池中時,如果池未滿,則會創(chuàng)建一個新的進(jìn)程用來執(zhí)行該請求;反之,如果池中的進(jìn)程數(shù)已經(jīng)達(dá)到規(guī)定大值,那么該請求就會等待,只要池中有進(jìn)程空閑下來,該請求就能得到執(zhí)行。
7.線程池系統(tǒng)中每個進(jìn)程里面至少包含一個 線程 。線程是操作系統(tǒng)創(chuàng)建的,每個線程對應(yīng)一個代碼執(zhí)行的數(shù)據(jù)結(jié)構(gòu),保存了代碼執(zhí)行過程中的重要的狀態(tài)信息。沒有線程,操作系統(tǒng)沒法管理和維護(hù) 代碼運(yùn)行的狀態(tài)信息。所以沒有創(chuàng)建線程之前,操作系統(tǒng)是不會執(zhí)行我們的代碼的。
8.同步和異步在一個進(jìn)程中,不同子線程負(fù)責(zé)不同的任務(wù),t1子線程負(fù)責(zé)獲取到數(shù)據(jù),t2子線程負(fù)責(zé)把數(shù)據(jù)保存的本地,那么他們之間的通信使用Queue來完成。因?yàn)樵僖粋€進(jìn)程中,數(shù)據(jù)變量是共享的,即多個子線程可以對同一個全局變量進(jìn)行操作修改,Queue是加了鎖的安全消息隊列。
Python的Queue隊列,主要用于多生產(chǎn)者和消費(fèi)者模式下的隊列實(shí)現(xiàn),特別適合多線程時的消息交換。通過使用隊列,把生產(chǎn)者和消費(fèi)者分解開來,作為其中的中間件,比如生產(chǎn)者產(chǎn)生一個數(shù)據(jù),然后放到queue隊列中,queue隊列在把這個數(shù)據(jù)放到消費(fèi)者線程中。使用單線程不必用隊列,但是隊列對于多線程來說是不可或缺的。
10.線程同步如果沒有控制多個線程對同一資源的訪問,對數(shù)據(jù)造成破壞,使得線程運(yùn)行的結(jié)果不可預(yù)期。這種現(xiàn)象稱為“線程不安全”。同步就是協(xié)同步調(diào),按預(yù)定的先后次序進(jìn)行運(yùn)行。
"同"字從字面上容易理解為一起動作,其實(shí)不是,"同"字應(yīng)是指協(xié)同、協(xié)助、互相配合。如進(jìn)程、線程同步,可理解為進(jìn)程或線程A和B一塊配合,A執(zhí)行到一定程度時要依靠B的某個結(jié)果,于是停下來,示意B運(yùn)行;B依言執(zhí)行,再將結(jié)果給A;A再繼續(xù)操作。
實(shí)現(xiàn)線程同步的方式可以是:
生產(chǎn)者消費(fèi)者模型具體來講,就是在一個系統(tǒng)中,存在生產(chǎn)者和消費(fèi)者兩種角色,他們通過內(nèi)存緩沖區(qū)進(jìn)行通信,生產(chǎn)者生產(chǎn)消費(fèi)者需要的資料,消費(fèi)者消耗數(shù)據(jù)或者資料。
舉一個寄信的例子,假設(shè)要寄一封信,大致過程如下:
Python 中,構(gòu)造線程的時候,可以設(shè)置daemon屬性,這個屬性必須再start()方法前設(shè)置好。線程daemon屬性,如果設(shè)定就是用戶的設(shè)置,否則就取當(dāng)前線程的daemon值。主線程是non-daemon線程,即daemon = False。線程具有一個daemon屬性,可以手動設(shè)置為True或者False,也可以不設(shè)置,則取默認(rèn)值為None。
如果除主線程之外還有non-daemon線程的時候,主線程退出時,也不會殺掉所有daemon線程,直到所有non-daemon線程全部結(jié)束,如果還有daemon線程,主線程需要退出,會結(jié)束所有daemon線程,程序退出。
13.鎖和共享內(nèi)存【多線程、多進(jìn)程涉及讀寫必須要用鎖,一定要用】
(1)多線程的線程鎖①死鎖問題和解決
如果多個線程要調(diào)用多個現(xiàn)象,而A線程調(diào)用A鎖占用了A對象,B線程調(diào)用了B鎖占用了B對象,A線程不能調(diào)用B對象,B線程不能調(diào)用A對象,于是一直等待。這就造成了線程“死鎖”。Threading模塊中,也有一個類,RLock,稱之為可重入鎖。該鎖對象內(nèi)部維護(hù)著一個Lock和一個counter對象。counter對象記錄了acquire的次數(shù),使得資源可以被多次require。最后,當(dāng)所有RLock被release后,其他線程才能獲取資源。在同一個線程中,RLock.acquire可以被多次調(diào)用,利用該特性,可以解決部分死鎖問題
②當(dāng)多個線程同時訪問一個數(shù)據(jù)時,需加鎖,排隊變成單線程一個一個執(zhí)行,避免出錯。
③加鎖避免并發(fā)導(dǎo)致邏輯出錯。
④每當(dāng)一個線程a要訪問共享數(shù)據(jù)時,必須先獲得鎖定;如果已經(jīng)有別的線程b獲得鎖定了,那么就讓線程a暫停,也就是同步阻塞;等到線程b訪問完畢,釋放鎖以后,再讓線程a繼續(xù)。
⑤同一時刻只允許一個線程操作該數(shù)據(jù),可以保證數(shù)據(jù)安全。 線程鎖用于鎖定資源,可以同時使用多個鎖,當(dāng)需要獨(dú)占某一資源時,任何一個鎖都可以鎖這個資源。
⑥將一段代碼鎖住,一旦獲得鎖權(quán)限,除非釋放線程鎖,否則其他代碼都無法獲得鎖權(quán)限。
(2)多進(jìn)程的進(jìn)程鎖①很多時候,需要在多個進(jìn)程中同時寫一個文件,如果不加鎖機(jī)制,就會導(dǎo)致寫文件錯亂。
②誰先搶到鎖誰先執(zhí)行,等到該進(jìn)程執(zhí)行完成后,其它進(jìn)程再搶鎖執(zhí)行。
③python多進(jìn)程編程使用進(jìn)程池非常的方便管理進(jìn)程,但是有時候子進(jìn)程之間會搶占一些獨(dú)占資源,比如consol或者比如日志文件的寫入權(quán)限,這樣的時候我們一般需要共享一個Lock來對獨(dú)占資源加鎖。
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧