Python - 高級教程 - 進程挖函、線程與協(xié)程
進程與線程
在操作系統(tǒng)中状植,每一個獨立運行的程序,都占有 操作系統(tǒng) 分配的資源怨喘,這些程序中間互不干涉津畸,都只負責運行自己的程序代碼,這就是進程哲思。
但是當操作系統(tǒng)頻繁的創(chuàng)建銷毀進程時洼畅,大量的系統(tǒng)資源被浪費在創(chuàng)建和銷毀的過程中。而隨著多核心cpu
的出現(xiàn)棚赔,線程也逐漸代替了進程帝簇,成為了操作系統(tǒng) 可以獨立運行的基本單位。
當進程不是多線程程序時靠益,存在于進程當中的唯一線程丧肴,便是進程本身運行的代碼塊。
而當多線程出現(xiàn)在一個進程中時胧后,則多個線程之間共享此進程的資源芋浮,并接受操作系統(tǒng)的調(diào)度來運行每個線程。
狀態(tài)
協(xié)程
為了了解協(xié)程的概念壳快,我們先來了解一下并發(fā)和并行纸巷。
并行
并行比較好理解,即有多個程序在同時執(zhí)行眶痰,這里的程序指的是操作系統(tǒng)的線程瘤旨。
每個 cpu
核心,只能在同一個時刻運行一組指令竖伯,意味著同一時刻存哲,一個核心上只有一個線程在執(zhí)行因宇。
當 cpu
有四個核心時,他只可以執(zhí)行4個線程祟偷。
并發(fā)
想要了解并發(fā)察滑,就需要知道和
。
同步阻塞
當程序中的一個 I/O
操作修肠,會占據(jù)比較長的時間贺辰,這時候,程序沒有被掛起氛赐,且一直在等待網(wǎng)絡數(shù)據(jù)傳輸魂爪,無法進行其他操作,這時候就是同步阻塞艰管。
同步的一個概念就是滓侍,網(wǎng)絡傳輸完成后也無法告知主程序操作完成,這就導致了主程序:
- 要么只能進行等待 I/O 完成
- 要么輪詢?nèi)ゲ榭词欠駛鬏斒欠褚呀?jīng)完成
當然牲芋,輪詢時候可以進行其他的操作撩笆,這時候,就是非阻塞的狀態(tài)缸浦,即 同步非阻塞夕冲。
同步非阻塞
非阻塞的概念即主程序可以進行其他的操作。
異步阻塞
有同步裂逐,就有異步歹鱼。
而異步阻塞與同步阻塞相同,主程序啥也不干卜高,就等著 I/O 操作完成弥姻。
異步非阻塞
異步非阻塞狀態(tài),便是并發(fā)的關鍵掺涛。
當主程序使用異步 I/O 操作時庭敦,并不會影響主程序后續(xù)的運行,而當異步 I/O 操作完成后薪缆,會主動通知主程序進行其他操作秧廉,這樣就減少了輪詢過程中的資源消耗,專注于其他工作拣帽。
并發(fā)
而并發(fā)就是 異步非阻塞
狀態(tài)下的一種形式疼电,當程序執(zhí)行操作 a 時,使 a 的 I/O 異步操作减拭,這時程序去執(zhí)行操作 b, 在外部看來澜沟,a 和 b 時同時被執(zhí)行的,然而他們只運行在在一個線程當中峡谊。
與線程、進程不同的是,協(xié)程并不是操作系統(tǒng)物理層面存在的一種程序既们。
協(xié)程是程序級別的濒析,由程序編寫者自己操控整個協(xié)程的生命周期。這樣就實現(xiàn)了類似操作系統(tǒng)操作多線程一樣的效果啥纸,但是省下了現(xiàn)成的切換中造成的資源消耗号杏。
而通過程序來操縱協(xié)程,就造成了cpu 一直在運行斯棒,并且是多個協(xié)程一直在運行的假象盾致,也就變成了并發(fā)。
實例
下面我們通過幾個實例來說明荣暮,在 python 中的進程庭惜、線程和協(xié)程的關系。
進程實例
在 python
中我們?nèi)绾尉帉懚噙M程的程序呢穗酥?
答案是使用模塊 multiprocessing
進行實現(xiàn)护赊。
import time
from multiprocessing import Process
class Test(Process):
def __init__(self):
super().__init__()
def run(self):
while True:
print("process b is run")
time.sleep(1)
通過繼承multiprocessing
的 Process
,實現(xiàn)進程類砾跃,然后實現(xiàn) run
方法骏啰,即可在此方法中實現(xiàn)進程要運行的內(nèi)容。
from process_b import Test
import time
if __name__ == "__main__":
t = Test()
t.start()
while True:
print("process a run")
time.sleep(1)
調(diào)用方法也非常簡單抽高,直接使用 Test
實例化對象判耕,然后調(diào)用對象的成員函數(shù)start()
即可。
python3 process_a.py
process a run
process b is run
process b is run
process a run
process a run
process b is run
process b is run
process a run
線程實例
Cpython
中由于存在 GIL
翘骂,所以多線程在實際應用中也會變?yōu)閱魏?code>cpu 上的線程壁熄,排隊運行。
import threading
import time
class ThreadTest (threading.Thread):
def __init__(self, name):
super().__init__()
self.name = name
def run(self):
while True:
print(f"i am in thread {self.name}")
time.sleep(1)
if __name__ == "__main__":
threads = []
for i in range(4):
t = ThreadTest(i)
threads.append(t)
for t in threads:
t.start()
for t in threads:
t.join()
通過繼承 threading.Thread
來實現(xiàn)線程類雏胃,然后通過實例化请毛,生成對象,調(diào)用對象的 start()
即可啟動線程瞭亮。
運行結果
python3 thread_a.py
i am in thread 0
i am in thread 1
i am in thread 2
i am in thread 3
i am in thread 1
i am in thread 3
i am in thread 0
i am in thread 2
i am in thread 1
i am in thread 3
i am in thread 0
i am in thread 2
i am in thread 1
協(xié)程
python3
將 asyncio
加入到了標準庫方仿。
import asyncio
import time
async def test(num):
await asyncio.sleep(num)
print(num)
async def run():
tasks = [asyncio.create_task(test(num)) for num in range(4)]
[await t for t in tasks]
def run_main():
asyncio.run(run())
if __name__ == "__main__":
run_main()
運行結果
import asyncio
import time
async def test(num):
await asyncio.sleep(num)
print(num)
async def run():
tasks = [asyncio.create_task(test(num)) for num in range(4)]
[await t for t in tasks]
def run_main():
asyncio.run(run())
if __name__ == "__main__":
run_main()
總結
以上就是本節(jié)的所有內(nèi)容,主要簡單地講解了關于 進程统翩、線程和協(xié)程
的概念和例子仙蚜。