導航:首頁 > 編程語言 > python多線程詳解

python多線程詳解

發布時間:2023-06-03 19:03:49

1. python中什麼是線程

線程是系統中的名詞,Python一般是單線程的,Python的多線程優化很差。
線程,有時被稱為輕量級進程(Lightweight Process,LWP),是程序執行流的最小單元。一個標準的線程由線程ID,當前指令指針(PC),寄存器集合和堆棧組成。另外,線程是進程中的一個實體,是被系統獨立調度和分派的基本單位,線程自己不擁有系統資源,只擁有一點兒在運行中必不可少的資源,但它可與同屬一個進程的其它線程共享進程所擁有的全部資源。一個線程可以創建和撤消另一個線程,同一進程中的多個線程之間可以並發執行。由於線程之間的相互制約,致使線程在運行中呈現出間斷性。線程也有就緒、阻塞和運行三種基本狀態。就緒狀態是指線程具備運行的所有條件,邏輯上可以運行,在等待處理機;運行狀態是指線程佔有處理機正在運行;阻塞狀態是指線程在等待一個事件(如某個信號量),邏輯上不可執行。每一個程序都至少有一個線程,若程序只有一個線程,那就是程序本身。
線程是程序中一個單一的順序控制流程。進程內有一個相對獨立的、可調度的執行單元,是系統獨立調度和分派CPU的基本單位指令運行時的程序的調度單位。在單個程序中同時運行多個線程完成不同的工作,稱為多線程。

2. python py文件同時開兩個線程可以嗎

可以的。
Python 多線程
多線程類似於同時執行多個不同程序,多線程運行有如下優點:

使用線程可以把占據長時間的程序中的任務放到後台去處理。
用戶界面可以更加吸引人,這樣比如用戶點擊了一個按鈕去觸發某些事件的處理,可以彈出一個進度條來顯示處理的進度
程序的運行速度可能加快
在一些等待的任務實現上如用戶輸入、文件讀寫和網路收發數據等,線程就比較有用了。在這種情況下我們可以釋放一些珍貴的資源如內存佔用等等。
線程在執行過程中與進程還是有區別的。每個獨立的進程有一個程序運行的入口、順序執行序列和程序的出口。但是線程不能夠獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制。

每個線程都有他自己的一組CPU寄存器,稱為線程的上下文,該上下文反映了線程上次運行該線程的CPU寄存器的狀態。

指令指針和堆棧指針寄存器是線程上下文中兩個最重要的寄存器,線程總是在進程得到上下文中運行的,這些地址都用於標志擁有線程的進程地址空間中的內存。

線程可以被搶占(中斷)。
在其他線程正在運行時,線程可以暫時擱置(也稱為睡眠) -- 這就是線程的退讓。

3. python 怎麼實現多線程的

線程也就是輕量級的進程,多線程允許一次執行多個線程,Python是多線程語言,它有一個多線程包,GIL也就是全局解釋器鎖,以確保一次執行單個線程,一個線程保存GIL並在將其傳遞給下一個線程之前執行一些操作,也就產生了並行執行的錯覺。

4. Python多線程總結

在實際處理數據時,因系統內存有限,我們不可能一次把所有數據都導出進行操作,所以需要批量導出依次操作。為了加快運行,我們會採用多線程的方法進行數據處理, 以下為我總結的多線程批量處理數據的模板:

主要分為三大部分:


共分4部分對多線程的內容進行總結。

先為大家介紹線程的相關概念:

在飛車程序中,如果沒有多線程,我們就不能一邊聽歌一邊玩飛車,聽歌與玩 游戲 不能並行;在使用多線程後,我們就可以在玩 游戲 的同時聽背景音樂。在這個例子中啟動飛車程序就是一個進程,玩 游戲 和聽音樂是兩個線程。

Python 提供了 threading 模塊來實現多線程:

因為新建線程系統需要分配資源、終止線程系統需要回收資源,所以如果可以重用線程,則可以減去新建/終止的開銷以提升性能。同時,使用線程池的語法比自己新建線程執行線程更加簡潔。

Python 為我們提供了 ThreadPoolExecutor 來實現線程池,此線程池默認子線程守護。它的適應場景為突發性大量請求或需要大量線程完成任務,但實際任務處理時間較短。

其中 max_workers 為線程池中的線程個數,常用的遍歷方法有 map 和 submit+as_completed 。根據業務場景的不同,若我們需要輸出結果按遍歷順序返回,我們就用 map 方法,若想誰先完成就返回誰,我們就用 submit+as_complete 方法。

我們把一個時間段內只允許一個線程使用的資源稱為臨界資源,對臨界資源的訪問,必須互斥的進行。互斥,也稱間接制約關系。線程互斥指當一個線程訪問某臨界資源時,另一個想要訪問該臨界資源的線程必須等待。當前訪問臨界資源的線程訪問結束,釋放該資源之後,另一個線程才能去訪問臨界資源。鎖的功能就是實現線程互斥。

我把線程互斥比作廁所包間上大號的過程,因為包間里只有一個坑,所以只允許一個人進行大號。當第一個人要上廁所時,會將門上上鎖,這時如果第二個人也想大號,那就必須等第一個人上完,將鎖解開後才能進行,在這期間第二個人就只能在門外等著。這個過程與代碼中使用鎖的原理如出一轍,這里的坑就是臨界資源。 Python 的 threading 模塊引入了鎖。 threading 模塊提供了 Lock 類,它有如下方法加鎖和釋放鎖:

我們會發現這個程序只會列印「第一道鎖」,而且程序既沒有終止,也沒有繼續運行。這是因為 Lock 鎖在同一線程內第一次加鎖之後還沒有釋放時,就進行了第二次 acquire 請求,導致無法執行 release ,所以鎖永遠無法釋放,這就是死鎖。如果我們使用 RLock 就能正常運行,不會發生死鎖的狀態。

在主線程中定義 Lock 鎖,然後上鎖,再創建一個子 線程t 運行 main 函數釋放鎖,結果正常輸出,說明主線程上的鎖,可由子線程解鎖。

如果把上面的鎖改為 RLock 則報錯。在實際中設計程序時,我們會將每個功能分別封裝成一個函數,每個函數中都可能會有臨界區域,所以就需要用到 RLock 。

一句話總結就是 Lock 不能套娃, RLock 可以套娃; Lock 可以由其他線程中的鎖進行操作, RLock 只能由本線程進行操作。

5. Python面試題,線程與進程的區別,Python中如何創建多線程

進程和線程

這兩個概念屬於操作系統,我們經常聽說,但是可能很少有人會細究它們的含義。對於工程師而言,兩者的定義和區別還是很有必要了解清楚的。

首先說進程,進程可以看成是 CPU執行的具體的任務 。在操作系統當中,由於CPU的運行速度非常快,要比計算機當中的其他設備要快得多。比如內存、磁碟等等,所以如果CPU一次只執行一個任務,那麼會導致CPU大量時間在等待這些設備,這樣操作效率很低。為了提升計算機的運行效率,把機器的技能盡可能壓榨出來,CPU是輪詢工作的。也就是說 它一次只執行一個任務,執行一小段碎片時間之後立即切換 ,去執行其他任務。

所以在早期的單核機器的時候,看起來電腦也是並發工作的。我們可以一邊聽歌一邊上網,也不會覺得卡頓。但實際上,這是CPU輪詢的結果。在這個例子當中,聽歌的軟體和上網的軟體對於CPU而言都是 獨立的進程 。我們可以把進程簡單地理解成運行的應用,比如在安卓手機裡面,一個app啟動的時候就會對應系統中的一個進程。當然這種說法不完全准確, 一個應用也是可以啟動多個進程的

進程是對應CPU而言的,線程則更多針對的是程序。即使是CPU在執行當前進程的時候,程序運行的任務其實也是有分工的。舉個例子,比如聽歌軟體當中,我們需要顯示歌詞的字幕,需要播放聲音,需要監聽用戶的行為,比如是否發生了切歌、調節音量等等。所以,我們需要 進一步拆分CPU的工作 ,讓它在執行當前進程的時候,繼續通過輪詢的方式來同時做多件事情。

進程中的任務就是線程,所以從這點上來說, 進程和線程是包含關系 。一個進程當中可以包含多個線程,對於CPU而言,不能直接執行線程,一個線程一定屬於一個進程。所以我們知道,CPU進程切換切換的是執行的應用程序或者是軟體,而進程內部的線程切換,切換的是軟體當中具體的執行任務。

關於進程和線程有一個經典的模型可以說明它們之間的關系,假設CPU是一家工廠,工廠當中有多個車間。不同的車間對應不同的生產任務,有的車間生產汽車輪胎,有的車間生產汽車骨架。但是工廠的電力是有限的,同時只能滿足一個廠房的使用。

為了讓大家的進度協調,所以工廠需要輪流提供各個車間的供電。 這里的車間對應的就是進程

一個車間雖然只生產一種產品,但是其中的工序卻不止一個。一個車間可能會有好幾條流水線,具體的生產任務其實是流水線完成的,每一條流水線對應一個具體執行的任務。但是同樣的, 車間同一時刻也只能執行一條流水線 ,所以我們需要車間在這些流水線之間切換供電,讓各個流水線生產進度統一。

這里車間里的 流水線自然對應的就是線程的概念 ,這個模型很好地詮釋了CPU、進程和線程之間的關系。實際的原理也的確如此,不過CPU中的情況要比現實中的車間復雜得多。因為對於進程和CPU來說,它們面臨的局面都是實時變化的。車間當中的流水線是x個,下一刻可能就成了y個。

了解完了線程和進程的概念之後,對於理解電腦的配置也有幫助。比如我們買電腦,經常會碰到一個術語,就是這個電腦的CPU是某某核某某線程的。比如我當年買的第一台筆記本是4核8線程的,這其實是在說這台電腦的CPU有 4個計算核心 ,但是使用了超線程技術,使得可以把一個物理核心模擬成兩個邏輯核心。相當於我們可以用4個核心同時執行8個線程,相當於8個核心同時執行,但其實有4個核心是模擬出來的虛擬核心。

有一個問題是 為什麼是4核8線程而不是4核8進程呢 ?因為CPU並不會直接執行進程,而是執行的是進程當中的某一個線程。就好像車間並不能直接生產零件,只有流水線才能生產零件。車間負責的更多是資源的調配,所以教科書里有一句非常經典的話來詮釋: 進程是資源分配的最小單元,線程是CPU調度的最小單元

啟動線程

Python當中為我們提供了完善的threading庫,通過它,我們可以非常方便地創建線程來執行多線程。

首先,我們引入threading中的Thread,這是一個線程的類,我們可以通過創建一個線程的實例來執行多線程。

from threading import Thread t = Thread(target=func, name='therad', args=(x, y)) t.start()

簡單解釋一下它的用法,我們傳入了三個參數,分別是 target,name和args ,從名字上我們就可以猜測出它們的含義。首先是target,它傳入的是一個方法,也就是我們希望多線程執行的方法。name是我們為這個新創建的線程起的名字,這個參數可以省略,如果省略的話,系統會為它起一個系統名。當我們執行Python的時候啟動的線程名叫MainThread,通過線程的名字我們可以做區分。args是會傳遞給target這個函數的參數。

我們來舉個經典的例子:

import time, threading # 新線程執行的代碼: def loop(n): print('thread %s is running...' % threading.current_thread().name) for i in range(n): print('thread %s >>> %s' % (threading.current_thread().name, i)) time.sleep(5) print('thread %s ended.' % threading.current_thread().name) print('thread %s is running...' % threading.current_thread().name) t = threading.Thread(target=loop, name='LoopThread', args=(10, )) t.start() print('thread %s ended.' % threading.current_thread().name)

我們創建了一個非常簡單的loop函數,用來執行一個循環來列印數字,我們每次列印一個數字之後這個線程會睡眠5秒鍾,所以我們看到的結果應該是每過5秒鍾屏幕上多出一行數字。

我們在Jupyter里執行一下:

表面上看這個結果沒毛病,但是其實有一個問題,什麼問題呢? 輸出的順序不太對 ,為什麼我們在列印了第一個數字0之後,主線程就結束了呢?另外一個問題是,既然主線程已經結束了, 為什麼Python進程沒有結束 , 還在向外列印結果呢?

因為線程之間是獨立的,對於主線程而言,它在執行了t.start()之後,並 不會停留,而是會一直往下執行一直到結束 。如果我們不希望主線程在這個時候結束,而是阻塞等待子線程運行結束之後再繼續運行,我們可以在代碼當中加上t.join()這一行來實現這點。

t.start() t.join() print('thread %s ended.' % threading.current_thread().name)

join操作可以讓主線程在join處掛起等待,直到子線程執行結束之後,再繼續往下執行。我們加上了join之後的運行結果是這樣的:

這個就是我們預期的樣子了,等待子線程執行結束之後再繼續。

我們再來看第二個問題,為什麼主線程結束的時候,子線程還在繼續運行,Python進程沒有退出呢?這是因為默認情況下我們創建的都是用戶級線程,對於進程而言, 會等待所有用戶級線程執行結束之後才退出 。這里就有了一個問題,那假如我們創建了一個線程嘗試從一個介面當中獲取數據,由於介面一直沒有返回,當前進程豈不是會永遠等待下去?

這顯然是不合理的,所以為了解決這個問題,我們可以把創建出來的線程設置成 守護線程

守護線程

守護線程即daemon線程,它的英文直譯其實是後台駐留程序,所以我們也可以理解成 後台線程 ,這樣更方便理解。daemon線程和用戶線程級別不同,進程不會主動等待daemon線程的執行, 當所有用戶級線程執行結束之後即會退出。進程退出時會kill掉所有守護線程

我們傳入daemon=True參數來將創建出來的線程設置成後台線程:

t = threading.Thread(target=loop, name='LoopThread', args=(10, ), daemon=True)

這樣我們再執行看到的結果就是這樣了:

這里有一點需要注意,如果你 在jupyter當中運行是看不到這樣的結果的 。因為jupyter自身是一個進程,對於jupyter當中的cell而言,它一直是有用戶級線程存活的,所以進程不會退出。所以想要看到這樣的效果,只能通過命令行執行Python文件。

如果我們想要等待這個子線程結束,就必須通過join方法。另外,為了預防子線程鎖死一直無法退出的情況, 我們還可以 在joih當中設置timeout ,即最長等待時間,當等待時間到達之後,將不再等待。

比如我在join當中設置的timeout等於5時,屏幕上就只會輸出5個數字。

另外,如果沒有設置成後台線程的話,設置timeout雖然也有用,但是 進程仍然會等待所有子線程結束 。所以屏幕上的輸出結果會是這樣的:

雖然主線程繼續往下執行並且結束了,但是子線程仍然一直運行,直到子線程也運行結束。

關於join設置timeout這里有一個坑,如果我們只有一個線程要等待還好,如果有多個線程,我們用一個循環將它們設置等待的話。那麼 主線程一共會等待N * timeout的時間 ,這里的N是線程的數量。因為每個線程計算是否超時的開始時間是上一個線程超時結束的時間,它會等待所有線程都超時,才會一起終止它們。

比如我這樣創建3個線程:

ths = [] for i in range(3): t = threading.Thread(target=loop, name='LoopThread' + str(i), args=(10, ), daemon=True) ths.append(t) for t in ths: t.start() for t in ths: t.join(2)

最後屏幕上輸出的結果是這樣的:

所有線程都存活了6秒。

總結

在今天的文章當中,我們一起簡單了解了 操作系統當中線程和進程的概念 ,以及Python當中如何創建一個線程,以及關於創建線程之後的相關使用。

多線程在許多語言當中都是至關重要的,許多場景下必定會使用到多線程。比如 web後端,比如爬蟲,再比如游戲開發 以及其他所有需要涉及開發ui界面的領域。因為凡是涉及到ui,必然會需要一個線程單獨渲染頁面,另外的線程負責准備數據和執行邏輯。因此,多線程是專業程序員繞不開的一個話題,也是一定要掌握的內容之一。

6. python同時打開幾個程序默認運行哪一個

操作系統的作用
隱藏醜陋復雜的硬體介面,提供良好的抽象介面
管理、調度進程,並且將多個進程對硬體的競爭變得有序
2. 多道技術產生背景

針對單核,實現並發
現在的主機一般是多核,那麼每個核都會利用多道技術
有 4 個 cpu,運行於 cpu1 的某個程序遇到 io 阻塞,會等到 io 結束再重新調度
會被調度到 4 個 cpu 中的任意一個,具體由操作系統調度演算法決定
3. 多道技術空間上的復用:如內存中同時有多道程序

4. 多道技術時間上的復用

復用一個 cpu 的時間片
注意,遇到 io 切,佔用 cpu 時間過長也切
核心在於切之前將進程的狀態保存下來
這樣才能保證下次切換回來時,能基於上次切走的位置繼續運行
進程的概念
進程是一個具有一定獨立功能的程序關於某個數據集合的一次運行活動
進程是操作系統動態執行的基本單元
在傳統的操作系統中,進程既是基本的分配單元,也是基本的執行單元
進程與程序的區別
程序是指令和數據的有序集合,是一個靜態的概念。程序可以作為一種軟體資料長期存在,是永久的
進程是程序在處理機上的一次執行過程,它是一個動態的概念。進程是有一定生命期的,是暫時的
5. 注意:同一個程序執行兩次,就會在操作系統中出現兩個進程。所以可以同時運行一個軟體,分別做不同的事情也不會混亂,比如可以打開兩個Pycharm做不同的事

6. 進程調度

要想多個進程交替運行,操作系統必須對這些進程進行調度
這個調度也不是隨即進行的,而是需要遵循一定的法則
由此就有了進程的調度演算法:先來先服務調度演算法、短作業優先調度演算法、時間片輪轉法、多級反饋隊列
並行和並發
並行是指在一個時間點上,有多個進程在被 cpu 計算,比如賽跑,兩個人都在不停的往前跑
並發是指資源有限的情況下,在一個時間段上,有多個進程在被 cpu 計算,交替輪流使用資源
並行與並發的區別
並行是從微觀上,也就是在一個精確的時間片刻,有不同的程序在執行,這就要求必須有多個處理器
並發是從宏觀上,在一個時間段上可以看出是同時執行的,比如一個伺服器同時處理多個 session
進程的三狀態
在程序運行的過程中,由於被操作系統的調度演算法控制,程序會進入幾個狀態
就緒
運行
阻塞
2. 舉例說明什麼是 argv,什麼是阻塞

import sys
print(sys.argv)

# 運行結果:
['G:/course_select/進程的概念.py']

# argv 指參數
# sys.argv 是 Python 解釋器在運行的時候傳遞進來的參數

# 首先在cmd輸入以下信息:
python G:/course_select/進程的概念.py
# 列印結果:
['G:/course_select/進程的概念.py']

# 然後在cmd中切換路徑到G盤,接著輸入 python course_select/進程的概念.py
# 列印結果:
['course_select/進程的概念.py']

# 接著,再在cmd中輸入:python course_select/進程的概念.py 123 abc
# 列印結果:
['course_select/進程的概念.py', '123', 'abc']

# 因此,以下程序不能在編輯器里運行,只能在 cmd 裡面使用 Python 運行本文件
# 然後要在後面加上 aaa bbb
# 就像上面的 python course_select/進程的概念.py 123 abc 一樣
if sys.argv[1] == "aaa" and sys.argv[2] == "bbb":
print("登錄成功")
else:
print("登錄失敗")
exit()
print(666)

# 而如果使用input(),其實就是一種阻塞
3. 進程的三狀態圖

.png
同步非同步
同步:形象的說,一件事的執行必須依賴另一件事的結束,強調的是順序性
非同步: 形象的說,兩件事情可以同時進行
注意:同步非同步和並行、並發沒關系
阻塞:等待,比如 input sleep recv accept recvfrom
非阻塞:不等待,start/terminate 都是非阻塞的
阻塞與非阻塞主要是從程序(線程)等待消息通知時的狀態角度來說的
可以分為四類:
同步阻塞
非同步阻塞
同步非阻塞
非同步非阻塞
start/terminate 都是非阻塞的
進程模塊
跟進程相關的基本都在這個模塊里:multiprocessing
父進程與子進程的對比分析
父進程,比如運行本文件
子進程,運行 Process(target=func).start()
父進程與子進程數據隔離
主進程等待子進程結束之後再結束
子進程和主進程之間默認是非同步的
from multiprocessing import Process
import time

def func():
time.sleep(1)
print(666)

if __name__ == "__main__":
# 開啟了一個新的進程,在這個新的進程里執行的 func()
Process(target=func).start()
time.sleep(1)
# 主進程
print(777)

# 777
# 666
# 運行結果仔細觀察發現有非同步的效果
# 也就是說,主進程和新的進程同時執行
3. 上面的示例中為什麼要有 if __name__ == "__main__"?其實這是 windows 操作系統開啟子進程的方式問題

4. 繼續深入

import time
import os
from multiprocessing import Process

def func():
time.sleep(1)
print(666, os.getpid(), os.getppid())

if __name__ == "__main__":
# 代碼執行到這里並不代表開啟了子進程
p = Process(target=func)
# 開啟了一個子進程,並執行func()
p.start()
time.sleep(1)
print(777, os.getpid(), os.getppid())

# 主進程運行的結果
777 12340 1636
# 子進程運行的結果
666 7604 12340

# 由上面兩行結果可以得出:
# 利用 os.getpid() 證明兩個進程不一樣
# 另外每次運行,os.getpid() 結果都不一樣
# 但是,12340 是主進程的 id,7604 是子進程的 id
# 1636 是 Pycharm 的 id,排列特點不變
5. 開啟多個相同的子進程示例

import time
import os
from multiprocessing import Process

def func():
time.sleep(3)
print(666, os.getpid(), os.getppid())

if __name__ == "__main__":
for i in range(10):
p = Process(target=func)
p.start()
time.sleep(1)
print(777, os.getpid(), os.getppid())

# 這里需要注意一點:Python 程序一直都是逐行執行
# 但是因為這里設置了時間延遲,因此會先執行主程序的代碼
# 運行結果:
777 29006 3833 # 暫停 2s 後再有下面的結果
666 29007 29006
666 29009 29006
666 29008 29006
666 29010 29006
666 29013 29006
666 29011 29006
666 29012 29006
666 29014 29006
666 29016 29006
666 29015 29006

# 觀察結果發現主進程只運行了一次
# 然後剩下的全是一個子進程重新運行的結果
# 主進程運行完不會結束,它會等子進程全部運行結束
# 注意變數 p 拿到的是最後一個子進程的 id
6. 開啟多個不同的子進程示例

import time
import os
from multiprocessing import Process

def func():
time.sleep(2)
print(666, os.getpid(), os.getppid())

def func2():
print(111)

if __name__ == "__main__":
for i in range(3):
p = Process(target=func)
p.start()
for i in range(2):
p = Process(target=func2)
p.start()
time.sleep(1)
print(777, os.getpid(), os.getppid())

# 運行程序時仔細觀察結果顯示順序:
111
111
777 29316 3833
666 29319 29316
666 29317 29316
666 29318 29316
7. 給子進程傳參示例

from multiprocessing import Process

def func(name):
print(666, name)

if __name__ == "__main__":
p = Process(target=func,args=(777,)) # 注意是一個元組
p.start()

import time
from multiprocessing import Process

def func(num, name):
time.sleep(1)
print(num, "hello", name)

if __name__ == "__main__":
for i in range(10):
p = Process(target=func, args=(i, "abc"))
p.start()
print("主進程")

# 運行結果:
666 777
主進程
0 hello abc
2 hello abc
1 hello abc
3 hello abc
5 hello abc
4 hello abc
6 hello abc
7 hello abc
8 hello abc
9 hello abc

# 多運行幾次,發現子進程並不是完全按順序運行的
# 比如上面先出結果 2 hello abc,再出結果 1 hello abc
8. 子進程可以有返回值嗎:不能有返回值,因為子進程函數中的返回值無法傳遞給父進程

import time
from multiprocessing import Process

def func():
time.sleep(3)
print("這是子進程,3s後才運行")

if __name__ == "__main__":
Process(target=func).start()
print("主進程")

# 運行結果:
主進程
這是子進程,3s後才運行

# 主進程會默認等待子進程結束之後才結束
# 因為父進程要負責回收子進程佔用的操作系統資源
相關資源:Python多進程寫入同一文件的方法_python多進程寫入同意文件-其它...
文章知識點與官方知識檔案匹配
Python入門技能樹首頁概覽
194693 人正在系統學習中
點擊閱讀全文
打開CSDN,閱讀體驗更佳

Python多進程(一)進程及進程池_程序員-夏天的博客
print("主進程結束") 通過上述代碼我們發現,multiprocessing.Process幫我們創建一個子進程,並且成功運行,但是我們發現,在子進程還沒執行完的時候主進程就已經死了,那麼這個子進程在主進程結束後就是一個孤兒進程,那麼我們可以讓主進程等待...
Python多進程之Process、Pool、Lock、Queue、Event、Semaphore、Pipe_大 ...
1. Python創建進程類Process python的multiprocessing模塊提供了一個創建進程的類Precess,其創建有以下兩種方法: 創建Process類的實例,並指向目標函數和傳遞參數 自定義一個類並繼承Process類,重寫__init__()和run()方法 ...
python兩個進程同時開啟只運行了一個_二十二、 深入Python的進程和線程(上篇)...
「@Author: Runsen」進程(Process)和線程(Thread)都是操作系統中的基本概念,它們之間有一些優劣和差異,那麼在Python中如何使用進程和線程?CPU計算機的核心是CPU,它承擔了計算機的所有計算任務,CPU就像一個工廠,時刻在運行著,而操作系統管理著計算機,負責任務的調度、資源的分配和管理。進程進程是指在系統中能獨立運行並作為資源分配的基本單位,它是由一組機器指令、數據...
繼續訪問
python啟動多個進程_Python多處理:只有一個進程正在運行
由於注釋表明您希望使用初始化程序和initargs參數傳遞featureVector.在Unix類型的系統上,這將導致大量的性能提升(即使selLabel中只有1個項目),因為該值將使用os.fork基本上免費傳遞給子進程.否則,每次調用foo時,featureVector都將被父進程pickle,通過管道傳遞並由子進程進行unpickled.這將花費很長時間,並且基本上將序列化所有子進程,因為它...
繼續訪問
python多進程多線程,多個程序同時運行_陳逸飛_p的博客_pyth...
python 模塊應用 開發工具 pycharm 實現方法 多任務的實現可以用進程和線程來實現 進程—> 線程---> 多任務應用 多進程操作 比如下載多個文件, 利用cpu 資源 提高效率 多任務: 同一時間執行多個任務, 比如windows操作系統 執行...
python多進程單例_Python多線程處理實例詳解【單進程/多進程】
python — 多線程處理 1、一個進程執行完後,繼續下一個進程 root@72132server:~# cd /root/python/multiprocess/ root@72132server:~/python/multiprocess# ls multprocess.py root@72132server:~/python/multiprocess# cat multprocess...
系統編程__2__父子進程的創建和回收
系統編程 這里寫的是對於小白來說更多的了解系統編程的文章,有寫的不對的地方還懇請各位大佬指出錯誤,小編一定會多多採納[手動多謝]。 那麼,上一次我們稍微了解了一下關於系統編程的一些主要內容[沒有看到的童鞋還請去上一篇文章稍微復習一下噢]。 這節課,我們先來想一想,我們為什麼要學系統編程呢?原因很簡單,我們要充分的利用CPU的性能,CPU和我們人類不太一樣,我們人類大多數情況下,在同一時間,只能完成一件事,而CPU作為無數科學家的心血當然不會這么簡單,CPU能夠同時進行多個進程,這里的進程我們可以理解成任務,
繼續訪問
android 10 system/core無法列印log問題
1.關閉重定向 system/core/init/util.cpp --- a/init/util.cpp +++ b/init/util.cpp @@ -454,7 +454,7 @@ static void InitAborter(const char* abort_message) { // SetStdioToDevNull() must be called again in second stage init. void SetStdioToDevNull(char** argv) { ...
繼續訪問
Python多進程1 一個多進程實例_BBJG_001的博客
下執行,job('主進程step1###')p1=mp.Process(target=job,args=('新進程>>>',))# 創建一個進程# 注意當只有一個參數的時候,一定要在參數後面加一個逗號,因為args需要是一個可以迭代的參量p1.start()# 開始執行新進程# p...
熱門推薦 python多進程多線程,多個程序同時運行
python 多線程 多進程同時運行 多任務要求 python 基礎語法 python 文件目錄操作 python 模塊應用 開發工具 pycharm 實現方法 多任務的實現可以用進程和線程來實現 進程—> 線程----> 多任務應用 多進程操作 比如下載多個文件, 利用cpu 資源 提高效率 多任務: 同一時間執行多個任務, 比如windows操作系統 執行方式有兩種( 表現形式 ) 並發 在單核cpu中: 在一段時間內交替執行多個任務, 例如單核cpu 處理多任務, 操作系統讓各個任務交
繼續訪問
fork()函數
多進程通信 fork()函數
繼續訪問
(1/7)Electron教程(一)什麼是 Electron,由來、適用場景 和 Electron 的環境搭建(1/7)
最近自己有個小的需求,是做一個能編輯本地特定文本的工具,需要跨平台, Windows 和 macOS,這樣,如果用原生開發的話,Windows 就要用c#macOS 就要用swift,學習成本高,並且學完用處也不是很大。我本身是前端開發的,發現了這個electron能滿足我的需求,跨平台運行,內部是 js 驅動的,簡直就是如魚得水。順便把學習的經歷寫出來,分享需要的人,我會按標題序號漸進式地編寫內容。electron。...
繼續訪問

fork()詳解
<一>: fork()函數用來創建新的進程,它的特點是調用一次返回兩次( 在原來的進程中返回新進程的 PID(新進程的 PID 肯定不等於 0), 在新進程中返回為 0.) 函數原型:pid_t fork(void); pid_t getpid(); 獲取當前進程的 pid 值。 pid_t getppid(); 獲取當前進程的父進程 pid 值。 圖一 如圖一所...
繼續訪問
fork()函數詳解
目錄 1.基本了解: 2.fork函數的了解: 3.僵死進程: 1.基本了解: 一個進程,包括代碼、數據和分配給進程的資源。fork 函數會新生成一個進程,調用 fork 函數的進程為父進程,新生成的進程為子進程。在父進程中返回子進程的 pid,在子進程中返回 0,失敗返回-1。 為什麼兩個進程的fpid不同呢,這與fork函數的特性有關。fork調用的一個奇妙之處就是它僅僅被調用一次,卻能夠返回兩次,它可能有三種不同的返回值: 1)在父進程中,fork返回新創建子進程的進程...
繼續訪問

Electron在Windows下的環境搭建
Electron作為一種用javascript寫桌面程序的開發方式,現在已經被大眾接受。下面就介紹如何在windows(>win7)下快速搭建Electron開發環境。 1. nodejs 的安裝 從nodejs 下載最新版本的windows安裝程序進行安裝,我下載的是v6.9.1,安裝時一路默認即可,這個安裝會把nodejs和npm配置到系統PATH中,這樣在命令行的任何位置都可以直接...
繼續訪問
python多線程pool_Python mutiprocessing多線程池pool操作示例
本文實例講述了Python mutiprocessing多線程池pool操作。分享給大家供大家參考,具體如下:python — mutiprocessing 多線程 pool腳本代碼:root@72132server:~/python/multiprocess# lsmultiprocess_pool.py multprocess.pyroot@72132server:~/python/multi...
繼續訪問
最新發布 python入門開發學習筆記之守護進程
本節重點 了解守護進程的概念 本節時長需控制在5分鍾內 一 守護進程 主進程創建子進程,然後將該進程設置成守護自己的進程,守護進程就好比崇禎皇帝身邊的老太監,崇禎皇帝已死老太監就跟著殉葬了。 關於守護進程需要強調兩點: 其一:守護進程會在主進程代碼執行結束後就終止 其二:守護進程內無法再開啟子進程,否則拋出異常:AssertionError: daemonic processes are not allowed to have children 如果我們有兩個任務需要並發執行,那麼開一個主進程和一個子進程分
繼續訪問
用python進行多進程編程時,只有主進程可以運行,子進程貌似沒有運行是什麼原因?
找了半天,原來是這個原因!這是因為multiprocessing模塊在交互模式是不支持的,在 cmd 里頭輸入 python xxx.py 來運行起來,你就可以看到子進程的執行了。
繼續訪問
linux中fork() 函數詳解
fork入門知識 一個進程,包括代碼、數據和分配給進程的資源。fork()函數通過系統調用創建一個與原來進程幾乎完全相同的進程,也就是兩個進程可以做完全相同的事,但如果初始參數或者傳入的變數不同,兩個進程也可以做不同的事。 一個進程調用fork()函數後,系統先給新的進程分配資源,例如存儲數據和代碼的空間。然後把原來的進程的所有值都復制到新的新進程中,只有少數值與原來的進程的值不同。相當於克隆了...
繼續訪問
Windows版 Node.js 安裝詳解以及Electron安裝
Windows Node.js 安裝詳解以及Electron安裝詳解,示例版本:node v10.15.0/npm6.4.1 介紹: 簡單的說 Node.js 就是運行在服務端的 JavaScript。 Node.js 是一個基於Chrome JavaScript 運行時建立的一個平台。 Node.js是一個事件驅動I/O服務端JavaScript環境,基於Google的V8引擎,V8引擎執...
繼續訪問

Electron 簡介
本教程我們來學習 Electron 的基礎知識,下面我們先來學習一下什麼是 Electron。 Electron是什麼 Electron 是是 GitHub 開發的一個開源框架。它允許使用 Node.js(作為後端)和 Chromium(作為前端)完成桌面 GUI 應用程序的開發。 Electron 可以用於構建具有 HTML、CSS、JavaScript 的跨平台桌面應用程序,它通過將 Chromium 和 node.js 合同一個運行的環境中來實現這一點,應用程序可以打包到 Mac、Windows 和
繼續訪問

Election的優缺點
優點 原生的介面(菜單、消息提醒、系統托盤等)。 上手難度低。能夠使用react、vue等前端框架,能方便地遷移前端組件,構建出漂亮的桌面應用。 方便熱更新 調試和測試方便 Electron使用node.js。因此,您可以導入Chrome應用程序中不容易使用的許多模塊 Electron文檔要好得多,盡管它是一個更年輕的平台 缺點 不適合開發輕量級的應用。即使一個electron的項目框架,也包含chromium內核,打包完接近200G。 相比c++開發的桌面應用,性能遠遠不如後者。 啟動速
繼續訪問
[electron]終極奧義 五千字教程丟給你
前言 本文包含打包、自動更新、簡易API、調試、進程通信等相關知識點,內容較多,可能會引起不適,請酌情查看(手動滑稽)。 electron 簡介 electron是由Github開發,是一個用Html、css、JavaScript來構建桌面應用程序的開源庫,可以打包為Mac、Windows、Linux系統下的應用。 electron是一個運行時環境,包含Node和Chromium,可以理解成把we...
繼續訪問
深入理解Java中的wait() 方法
使用場景 當某個線程獲取到鎖後,發現當前還不滿足執行的條件,就可以調用對象鎖的wait方法,進入等待狀態。 直到某個時刻,外在條件滿足了,就可以由其他線程通過調用notify()或者notifyAll()方法,來喚醒此線程。 這篇文章將側重於討論wait()方法對於線程狀態的影響,以及被喚醒後線程的狀態變更。 條件 只有已經獲取鎖的線程,才可以調用鎖的wait方法,否則會拋出異常IllegalMonitorStateException。 比如下面的代碼,A獲得了鎖後,主動調用wait方法釋放鎖和
繼續訪問

用Electron開發桌面應用的避坑指南(文末送書)
送一波高質量Web開發圖書,送5本書籍,隨你挑。抽獎規則見本文最後!抽獎規則見本文最後!抽獎規則見本文最後!如今,Electron 領域發生了重大的變革,Electron 版本更新換代極快...
繼續訪問

python多進程只有一個進程在執行
python兩個進程同時開啟只運行了一個。

7. Python多線程是什麼意思

多線程能讓你像運行一個獨立的程序一樣運行一段長代碼。這有點像調用子進程(subprocess),不過區別是你調用shu的是一個函數或者一個類,而不是獨立的程序。
程基本上是一個獨立執行流程。單個進程可以由多個線程組成。程序中的每個線程都執行特定的任務。例如,當你在電腦上玩游戲時,比如說國際足聯,整個游戲是一個單一的過程。,但它由幾個線程組成,負責播放音樂、接收用戶的輸入、同步運行對手等。所有這些都是單獨的線程,負責在同一個程序中執行這些不同的任務。
每個進程都有一個始終在運行的線程。這是主線。這個主線程實際上創建子線程對象。子線程也由主線程啟動。

8. python 多線程和多進程的區別 mutiprocessing theading

首先你要搞清楚進程和線程的關系:線程是最小的執行單元,而進程由至少一個線程組成。

multiprocessing模塊是一個跨平台版本的多進程模塊。該模塊提供了process類來代表一個進程對象。

Process

構造方法__init__(self, group=None, target=None, name=None, args=(), kwargs={})

參數說明:

group:進程所屬組。基本不用

target:表示調用對象或方法名稱。

args:表示調用對象的位置參數元組。

name:別名

kwargs:表示調用對象的字典。

示例代碼如下:

threading本身就可以創建多個線程:

hreads = []#定義一個線程池

t1 = threading.Thread(target=one,args=(,))#建立一個線程並且賦給t1,這個線程指定調用方法one,並且不帶參數

threads.append(t1)#把t1線程裝到threads線程池裡

t2 = threading.Thread(target=two)

threads.append(t2)

t3 = threading.Thread(target=three)

threads.append(t3)

這時threads這個列表中就有三個線程裝在裡面了。

下面就是運行這個線程池裡面的線程

for t in threads:

用一個for語句遍歷threads里的線程,然後調用start()方法運行

注意t.join()必須放在for語句外面。

9. python中多進程和多線程的區別

什麼是線程、進程?
進程(process)與線程(thread)是操作系統的基本概念,它們比較抽象,不容易掌握。
關於這兩者,最經典的一句話就是「進程是資源分配的最小單位,線程是CPU調度的最小單位」,線程是程序中一個單一的順序控制流程,進程內一個相對獨立的、可調度的執行單元,是系統獨立調度和分配CPU的基本單位指運行中的程序的調度單位,在單個程序中同時運行多個線程完成不同的工作,稱為多線程。
進程與線程的區別是什麼?
進程是資源分配的基本單位,所有與該進程有關的資源,都被記錄在進程式控制制塊PCB中,以表示該進程擁有這些資源或正在使用它們,另外,進程也是搶占處理機的調度單位,它擁有一個完整的虛擬地址空間,當進程發生調度時,不同的進程擁有不同的虛擬地址空間,而同一進程內的不同線程共享同一地址空間。
與進程相對應的,線程與資源分配無關,它屬於某一個進程,並與進程內的其他線程一起共享進程的資源,線程只由相關堆棧(系統棧或用戶棧)寄存器和線程式控制製表TCB組成,寄存器可被用來存儲線程內的局部變數,但不能存儲其他線程的相關變數。
通常在一個進程中可以包含若干個線程,它們可以利用進程所擁有的資源,在引入線程的操作系統中,通常都是把進程作為分配資源的基本單位,而把線程作為獨立運行和獨立調度的基本單位。
由於線程比進程更小,基本上不擁有系統資源,所以對它的調度所付出的開銷就會小得多,能更高效的提高系統內多個程序間並發執行的程度,從而顯著提高系統資源的利用率和吞吐量。
因而近年來推出的通用操作系統都引入了線程,以便進一步提高系統的並發性,並把它視為現代操作系統的一個重要指標。

10. 一篇文章帶你深度解析Python線程和進程

使用Python中的線程模塊,能夠同時運行程序的不同部分,並簡化設計。如果你已經入門Python,並且想用線程來提升程序運行速度的話,希望這篇教程會對你有所幫助。

線程與進程

什麼是進程

進程是系統進行資源分配和調度的一個獨立單位 進程是具有一定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位。每個進程都有自己的獨立內存空間,不同進程通過進程間通信來通信。由於進程比較重量,占據獨立的內存,所以上下文進程間的切換開銷(棧、寄存器、虛擬內存、文件句柄等)比較大,但相對比較穩定安全。

什麼是線程

CPU調度和分派的基本單位 線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.線程自己基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源。線程間通信主要通過共享內存,上下文切換很快,資源開銷較少,但相比進程不夠穩定容易丟失數據。

進程與線程的關系圖

線程與進程的區別:

進程

現實生活中,有很多的場景中的事情是同時進行的,比如開車的時候 手和腳共同來駕駛 汽車 ,比如唱歌跳舞也是同時進行的,再比如邊吃飯邊打電話;試想如果我們吃飯的時候有一個領導來電,我們肯定是立刻就接聽了。但是如果你吃完飯再接聽或者回電話,很可能會被開除。

注意:

多任務的概念

什麼叫 多任務 呢?簡單地說,就是操作系統可以同時運行多個任務。打個比方,你一邊在用瀏覽器上網,一邊在聽MP3,一邊在用Word趕作業,這就是多任務,至少同時有3個任務正在運行。還有很多任務悄悄地在後台同時運行著,只是桌面上沒有顯示而已。

現在,多核CPU已經非常普及了,但是,即使過去的單核CPU,也可以執行多任務。由於CPU執行代碼都是順序執行的,那麼,單核CPU是怎麼執行多任務的呢?

答案就是操作系統輪流讓各個任務交替執行,任務1執行0.01秒,切換到任務2,任務2執行0.01秒,再切換到任務3,執行0.01秒,這樣反復執行下去。表面上看,每個任務都是交替執行的,但是,由於CPU的執行速度實在是太快了,我們感覺就像所有任務都在同時執行一樣。

真正的並行執行多任務只能在多核CPU上實現,但是,由於任務數量遠遠多於CPU的核心數量,所以,操作系統也會自動把很多任務輪流調度到每個核心上執行。 其實就是CPU執行速度太快啦!以至於我們感受不到在輪流調度。

並行與並發

並行(Parallelism)

並行:指兩個或兩個以上事件(或線程)在同一時刻發生,是真正意義上的不同事件或線程在同一時刻,在不同CPU資源呢上(多核),同時執行。

特點

並發(Concurrency)

指一個物理CPU(也可以多個物理CPU) 在若幹道程序(或線程)之間多路復用,並發性是對有限物理資源強制行使多用戶共享以提高效率。

特點

multiprocess.Process模塊

process模塊是一個創建進程的模塊,藉助這個模塊,就可以完成進程的創建。

語法:Process([group [, target [, name [, args [, kwargs]]]]])

由該類實例化得到的對象,表示一個子進程中的任務(尚未啟動)。

注意:1. 必須使用關鍵字方式來指定參數;2. args指定的為傳給target函數的位置參數,是一個元祖形式,必須有逗號。

參數介紹:

group:參數未使用,默認值為None。

target:表示調用對象,即子進程要執行的任務。

args:表示調用的位置參數元祖。

kwargs:表示調用對象的字典。如kwargs = {'name':Jack, 'age':18}。

name:子進程名稱。

代碼:

除了上面這些開啟進程的方法之外,還有一種以繼承Process的方式開啟進程的方式:

通過上面的研究,我們千方百計實現了程序的非同步,讓多個任務可以同時在幾個進程中並發處理,他們之間的運行沒有順序,一旦開啟也不受我們控制。盡管並發編程讓我們能更加充分的利用IO資源,但是也給我們帶來了新的問題。

當多個進程使用同一份數據資源的時候,就會引發數據安全或順序混亂問題,我們可以考慮加鎖,我們以模擬搶票為例,來看看數據安全的重要性。

加鎖可以保證多個進程修改同一塊數據時,同一時間只能有一個任務可以進行修改,即串列的修改。加鎖犧牲了速度,但是卻保證了數據的安全。

因此我們最好找尋一種解決方案能夠兼顧:1、效率高(多個進程共享一塊內存的數據)2、幫我們處理好鎖問題。

mutiprocessing模塊為我們提供的基於消息的IPC通信機制:隊列和管道。隊列和管道都是將數據存放於內存中 隊列又是基於(管道+鎖)實現的,可以讓我們從復雜的鎖問題中解脫出來, 我們應該盡量避免使用共享數據,盡可能使用消息傳遞和隊列,避免處理復雜的同步和鎖問題,而且在進程數目增多時,往往可以獲得更好的可獲展性( 後續擴展該內容 )。

線程

Python的threading模塊

Python 供了幾個用於多線程編程的模塊,包括 thread, threading 和 Queue 等。thread 和 threading 模塊允許程序員創建和管理線程。thread 模塊 供了基本的線程和鎖的支持,而 threading 供了更高級別,功能更強的線程管理的功能。Queue 模塊允許用戶創建一個可以用於多個線程之間 共享數據的隊列數據結構。

python創建和執行線程

創建線程代碼

1. 創建方法一:

2. 創建方法二:

進程和線程都是實現多任務的一種方式,例如:在同一台計算機上能同時運行多個QQ(進程),一個QQ可以打開多個聊天窗口(線程)。資源共享:進程不能共享資源,而線程共享所在進程的地址空間和其他資源,同時,線程有自己的棧和棧指針。所以在一個進程內的所有線程共享全局變數,但多線程對全局變數的更改會導致變數值得混亂。

代碼演示:

得到的結果是:

首先需要明確的一點是GIL並不是Python的特性,它是在實現Python解析器(CPython)時所引入的一個概念。就好比C++是一套語言(語法)標准,但是可以用不同的編譯器來編譯成可執行代碼。同樣一段代碼可以通過CPython,PyPy,Psyco等不同的Python執行環境來執行(其中的JPython就沒有GIL)。

那麼CPython實現中的GIL又是什麼呢?GIL全稱Global Interpreter Lock為了避免誤導,我們還是來看一下官方給出的解釋:

主要意思為:

因此,解釋器實際上被一個全局解釋器鎖保護著,它確保任何時候都只有一個Python線程執行。在多線程環境中,Python 虛擬機按以下方式執行:

由於GIL的存在,Python的多線程不能稱之為嚴格的多線程。因為 多線程下每個線程在執行的過程中都需要先獲取GIL,保證同一時刻只有一個線程在運行。

由於GIL的存在,即使是多線程,事實上同一時刻只能保證一個線程在運行, 既然這樣多線程的運行效率不就和單線程一樣了嗎,那為什麼還要使用多線程呢?

由於以前的電腦基本都是單核CPU,多線程和單線程幾乎看不出差別,可是由於計算機的迅速發展,現在的電腦幾乎都是多核CPU了,最少也是兩個核心數的,這時差別就出來了:通過之前的案例我們已經知道,即使在多核CPU中,多線程同一時刻也只有一個線程在運行,這樣不僅不能利用多核CPU的優勢,反而由於每個線程在多個CPU上是交替執行的,導致在不同CPU上切換時造成資源的浪費,反而會更慢。即原因是一個進程只存在一把gil鎖,當在執行多個線程時,內部會爭搶gil鎖,這會造成當某一個線程沒有搶到鎖的時候會讓cpu等待,進而不能合理利用多核cpu資源。

但是在使用多線程抓取網頁內容時,遇到IO阻塞時,正在執行的線程會暫時釋放GIL鎖,這時其它線程會利用這個空隙時間,執行自己的代碼,因此多線程抓取比單線程抓取性能要好,所以我們還是要使用多線程的。

GIL對多線程Python程序的影響

程序的性能受到計算密集型(CPU)的程序限制和I/O密集型的程序限制影響,那什麼是計算密集型和I/O密集型程序呢?

計算密集型:要進行大量的數值計算,例如進行上億的數字計算、計算圓周率、對視頻進行高清解碼等等。這種計算密集型任務雖然也可以用多任務完成,但是花費的主要時間在任務切換的時間,此時CPU執行任務的效率比較低。

IO密集型:涉及到網路請求(time.sleep())、磁碟IO的任務都是IO密集型任務,這類任務的特點是CPU消耗很少,任務的大部分時間都在等待IO操作完成(因為IO的速度遠遠低於CPU和內存的速度)。對於IO密集型任務,任務越多,CPU效率越高,但也有一個限度。

當然為了避免GIL對我們程序產生影響,我們也可以使用,線程鎖。

Lock&RLock

常用的資源共享鎖機制:有Lock、RLock、Semphore、Condition等,簡單給大家分享下Lock和RLock。

Lock

特點就是執行速度慢,但是保證了數據的安全性

RLock

使用鎖代碼操作不當就會產生死鎖的情況。

什麼是死鎖

死鎖:當線程A持有獨占鎖a,並嘗試去獲取獨占鎖b的同時,線程B持有獨占鎖b,並嘗試獲取獨占鎖a的情況下,就會發生AB兩個線程由於互相持有對方需要的鎖,而發生的阻塞現象,我們稱為死鎖。即死鎖是指多個進程因競爭資源而造成的一種僵局,若無外力作用,這些進程都將無法向前推進。

所以,在系統設計、進程調度等方面注意如何不讓這四個必要條件成立,如何確定資源的合理分配演算法,避免進程永久占據系統資源。

死鎖代碼

python線程間通信

如果各個線程之間各干各的,確實不需要通信,這樣的代碼也十分的簡單。但這一般是不可能的,至少線程要和主線程進行通信,不然計算結果等內容無法取回。而實際情況中要復雜的多,多個線程間需要交換數據,才能得到正確的執行結果。

python中Queue是消息隊列,提供線程間通信機制,python3中重名為為queue,queue模塊塊下提供了幾個阻塞隊列,這些隊列主要用於實現線程通信。

在 queue 模塊下主要提供了三個類,分別代表三種隊列,它們的主要區別就在於進隊列、出隊列的不同。

簡單代碼演示

此時代碼會阻塞,因為queue中內容已滿,此時可以在第四個queue.put('蘋果')後面添加timeout,則成為 queue.put('蘋果',timeout=1)如果等待1秒鍾仍然是滿的就會拋出異常,可以捕獲異常。

同理如果隊列是空的,無法獲取到內容默認也會阻塞,如果不阻塞可以使用queue.get_nowait()。

在掌握了 Queue 阻塞隊列的特性之後,在下面程序中就可以利用 Queue 來實現線程通信了。

下面演示一個生產者和一個消費者,當然都可以多個

使用queue模塊,可在線程間進行通信,並保證了線程安全。

協程

協程,又稱微線程,纖程。英文名Coroutine。

協程是python個中另外一種實現多任務的方式,只不過比線程更小佔用更小執行單元(理解為需要的資源)。為啥說它是一個執行單元,因為它自帶CPU上下文。這樣只要在合適的時機, 我們可以把一個協程 切換到另一個協程。只要這個過程中保存或恢復 CPU上下文那麼程序還是可以運行的。

通俗的理解:在一個線程中的某個函數,可以在任何地方保存當前函數的一些臨時變數等信息,然後切換到另外一個函數中執行,注意不是通過調用函數的方式做到的,並且切換的次數以及什麼時候再切換到原來的函數都由開發者自己確定。

在實現多任務時,線程切換從系統層面遠不止保存和恢復 CPU上下文這么簡單。操作系統為了程序運行的高效性每個線程都有自己緩存Cache等等數據,操作系統還會幫你做這些數據的恢復操作。所以線程的切換非常耗性能。但是協程的切換只是單純的操作CPU的上下文,所以一秒鍾切換個上百萬次系統都抗的住。

greenlet與gevent

為了更好使用協程來完成多任務,除了使用原生的yield完成模擬協程的工作,其實python還有的greenlet模塊和gevent模塊,使實現協程變的更加簡單高效。

greenlet雖說實現了協程,但需要我們手工切換,太麻煩了,gevent是比greenlet更強大的並且能夠自動切換任務的模塊。

其原理是當一個greenlet遇到IO(指的是input output 輸入輸出,比如網路、文件操作等)操作時,比如訪問網路,就自動切換到其他的greenlet,等到IO操作完成,再在適當的時候切換回來繼續執行。

模擬耗時操作:

如果有耗時操作也可以換成,gevent中自己實現的模塊,這時候就需要打補丁了。

使用協程完成一個簡單的二手房信息的爬蟲代碼吧!

以下文章來源於Python專欄 ,作者宋宋

文章鏈接:https://mp.weixin.qq.com/s/2r3_ipU3HjdA5VnqSHjUnQ

閱讀全文

與python多線程詳解相關的資料

熱點內容
如何把命令框里的輸出到窗口 瀏覽:529
離線版mc如何開伺服器 瀏覽:884
結對程序員 瀏覽:766
使用過的蘋果手機怎麼同步app 瀏覽:344
phpcookie無效 瀏覽:954
python可以搜數學答案 瀏覽:706
均線衍生指標源碼設置 瀏覽:496
做精一張圖pdf 瀏覽:851
編程培訓小朋友 瀏覽:787
巴克球製作解壓 瀏覽:851
測量參數時接單片機的 瀏覽:116
手機音樂添加文件夾 瀏覽:546
百度智能雲b18怎麼刪除app 瀏覽:968
單片機中為什麼顯示找不到頭文件 瀏覽:151
iisweb伺服器如何重啟 瀏覽:838
微信沒有適配方舟編譯器 瀏覽:81
箍筋加密區梁的凈高 瀏覽:889
samp如何加入外國伺服器 瀏覽:895
保鮮膜解壓教學視頻 瀏覽:983
台達plc編程通訊管理軟體 瀏覽:407