纖程/協程詳細總結

看了一大堆講協程的文章,都是看的似懂非懂,自己學習後就寫一個總結了

微內核/宏內核

進程,線程,纖程/協程定義

進程資源分配最小單位,線程CPU調度/執行最小單位。
當運行一個程序,點擊一次則啓動一個進程放入內存執行,進程內UI,socket等功能並行運行。
這時候線程並行運行這些功能,線程不會額外分配內存空間,線程都共享所處進程內存空間

PC寄存器記錄線程內數據執行到哪,CPU通過PC寄存器取數據計算,循環反覆。
JVM內調用OS啓動分配線程內存消耗1mb左右,開銷巨大。所以爲了減小線程上下文切換巨大開銷,協程出現了。
JAVA的JMM中,每個線程都有自己的線程棧,協程模擬記錄了PC stack/線程棧信息,不經過操作系統。
一個線程包含多個協程,JAVA不支持協程目前

以前負載均衡中間件文章寫Nginx,lua那也提過協程

類似多線程,不是操作系統線程,所以創建切換開銷比線程小
協程棧在用戶進程空間模擬的,所以創建切換開銷小
多線程是併發執行,一個瞬間多個流執行。協程強調協作,一瞬間能有一個運行
因爲一瞬間只能一個運行,對臨界區不用加鎖,多線程則需要加
因爲多線程有多個控制流,程序行爲不可控,協程可控

優點:	
	1. 協程的切換開銷更小,屬於程序級別的切換,操作系統完全感知不到,因而更加輕量級  
   	2. 單線程內就可以實現併發的效果,最大限度地利用cpu
   	3. 程序行爲可控
缺點:
 	1. 協程的本質是單線程下,無法利用多核,可以是一個程序開啓多個進程,每個進程內開啓多個線程,每個線程內開啓協程
 	2. 協程指的是單個線程,因而一旦協程出現阻塞,將會阻塞整個線程

Nginx每個worker進程都在epoll/kqueue上封裝成協程,每個請求一個協程處理,與lua內建協程模型一致。
所以ngx_lua執行lua對c開銷很小,高併發能力仍然很好

應用

	C語言常採用回調的方法:當異步完成時,回調腳本的一個已知的函數。如果程序執行到異步點時,跳回,當異步完成後,再回到跳回點繼續執行。
	協程主要可以用於回調,協程是把異步過程,當作同步處理。

	比如JAVA中callable和future實現異步,JAVA仍然需要新建一個線程主動尋找結果
	Guava添加了監聽器不需要主動尋找結果等,都不是很好。因爲0x80中斷/sysenter原語,
	用戶態向內核態發送80中斷,比如申請read函數,總要有很大內核上下文切換開銷
		1 用戶態發出80中斷
		2 切換內核態
		3 中斷向量表中查找read函數
		4 保存硬件現場,CS IP等寄存器值
		5 保存用戶態程序堆棧和寄存器值
		6 執行中斷例程,system call
			根據參數和找到的read函數,執行並返回
		7 恢復硬件現場
		8 返回用戶態
		9 程序繼續執行

	read的IO時間過長,多線程下會放棄CPU執行權,交於其他線程執行,會通過OS切換額外開銷。
	單線程內開啓協程,一旦遇到io,就會從應用程序級別(而非操作系統)控制切換,以此來提升效率(非io操作的切換與效率無關。
	所以如果使用協程,免去上下文切換,性能能大幅度提升
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章