進擊のpython
並發編程——進程理論
基於上一小節,相信對計算機的操作系統的發展史有了大致的了解
那這一小節我們對以下幾個方面進行展開:
1.什么是進程
2.並發與並行
3.進程創建的方式
4.進程的三種狀態
什么是進程
進程,進行的程序,這是一個狀態。
一個正在進行的程序或者是一個任務都可以稱為進程
而執行任務的就是CPU
進程與程序有什么區別呢?程序是一個名詞,就是一堆復雜的代碼體,而進程就是執行程序的過程
並發與並行
其實說句題外話無論是並行還是並發,在用戶看來,程序都是“同時”進行的
而對於進程還是線程來說,都是同一個任務,真正在工作的就是CPU
一個CPU在同一時刻只能做同一個任務
並發
並發其實是偽並行,看起來是同時運行的,可以通過單個CPU+多道技術來實現
就像夏天的你在空調屋,一邊喝着啤酒,一邊吃着炸雞,一邊追劇
那就應該是吃幾口炸雞,然后停下來,去喝啤酒,然后抬頭看看韓劇
你在同一時刻只能喝啤酒或者吃炸雞(一個CPU在同一時刻只能做同一個任務)
但是別人看上去就是在同時進行的
並行
並行才是真正的同時運行,只有具備多個CPU才能實現並行
單核下,可以利用多道技術;多核下,每個核也可以利用多道技術
現在有四核六個任務,執行順序是怎么樣的?
CPU1,CPU2,CPU3,CPU4同時執行任務1~4
當1~4某個任務遇到I/O,就被迫中斷,此時任務5就來使用這個CPU
而中斷任務的I/O結束了,操作系統就會重新調用(需知進程的調度、分配給哪個CPU運行,由操作系統說了算)
可能是CPU1~4的任意一個
進程的創建
是個計算機,他就得有硬件參與,有硬件參與就一定有操作系統
而由操作系統,就會有進程的概念,也就需要一個創建的方式
而像一些簡單的操作系統,只服務於一個應用程序,比如掃地機器人
那對於像電腦里面的這種通用系統來說,就需要有系統運行過程中創建和銷毀進程的能力
創建新的進程,總共有四種方式
- 系統初始化(查看進程linux中用ps命令,windows中用任務管理器,前台進程負責與用戶交互,后台運行的進程與用戶無關,運行在后台並且只在需要時才喚醒的進程,稱為守護進程,如電子郵件、web頁面、新聞、打印)
- 一個進程在運行過程中開啟了子進程(如nginx開啟多進程,os.fork,subprocess.Popen等)
- 用戶的交互式請求,而創建一個新進程(如用戶雙擊暴風影音)
- 一個批處理作業的初始化(只在大型機的批處理系統中應用)
無論哪一種,新進程的創建都是由一個已經存在的進程執行了一個用於創建進程的系統調用而創建的:
- 在UNIX中該系統調用是:fork,fork會創建一個與父進程一模一樣的副本,二者有相同的存儲映像、同樣的環境字符串和同樣的打開文件(在shell解釋器進程中,執行一個命令就會創建一個子進程)
- 在windows中該系統調用是:CreateProcess,CreateProcess既處理進程的創建,也負責把正確的程序裝入新進程。
無論哪一種,新進程的創建都是由一個已經存在的進程執行了一個用於創建進程的系統調用而創建的:
- 在UNIX中該系統調用是:fork,fork會創建一個與父進程一模一樣的副本,二者有相同的存儲映像、同樣的環境字符串和同樣的打開文件(在shell解釋器進程中,執行一個命令就會創建一個子進程)
- 在windows中該系統調用是:CreateProcess,CreateProcess既處理進程的創建,也負責把正確的程序裝入新進程。
關於創建的子進程,UNIX和windows
1.相同的是:進程創建后,父進程和子進程有各自不同的地址空間(多道技術要求物理層面實現進程之間內存的隔 離),任何一個進程的在其地址空間中的修改都不會影響到另外一個進程。
2.不同的是:在UNIX中,子進程的初始地址空間是父進程的一個副本,提示:子進程和父進程是可以有只讀的共享內 存區的。但是對於windows系統來說,從一開始父進程與子進程的地址空間就是不同的。
那有創建,就有終止,進程的終止一般有以下的幾種方式
- 正常退出(自願,如用戶點擊交互式頁面的叉號,或程序執行完畢調用發起系統調用正常退出,在linux中用exit,在windows中用ExitProcess)
- 出錯退出(自願,python a.py中a.py不存在)
- 嚴重錯誤(非自願,執行非法指令,如引用不存在的內存,1/0等,可以捕捉異常,try…except…)
- 被其他進程殺死(非自願,如kill -9)
進程的三種狀態
tail -f access.log |grep '404'
執行程序tail,開啟一個子進程,執行程序grep,開啟另外一個子進程,兩個進程之間基於管道'|'通訊,將tail的結果作為grep的輸入。
進程grep在等待輸入(即I/O)時的狀態稱為阻塞,此時grep命令都無法運行
其實在兩種情況下會導致一個進程在邏輯上不能運行,
1. 進程掛起是自身原因,遇到I/O阻塞,便要讓出CPU讓其他進程去執行,這樣保證CPU一直在工作
2. 與進程無關,是操作系統層面,可能會因為一個進程占用時間過多,或者優先級等原因,而調用其他的進程去使用CPU。
因而一個進程有三種狀態