0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

談?wù)剠f(xié)程的那些事兒

jf_uPRfTJDa ? 來源: 移動Labs ? 2024-01-26 11:36 ? 次閱讀

Labs 導(dǎo)讀

隨著異步編程的發(fā)展以及各種并發(fā)框架的普及,協(xié)程作為一種異步編程規(guī)范在各類語言中地位逐步提高。我們不單單會在自己的程序中使用協(xié)程,各類框架如fastapi,aiohttp等也都是基于異步以及協(xié)程進(jìn)行實現(xiàn)。那到底什么是協(xié)程?協(xié)程是怎么發(fā)展來的呢?本文將會對這些問題做一個深入淺出的介紹。

作者:李佳斌

單位:中國移動智慧家庭運(yùn)營中心

本期Labs帶大家認(rèn)識下

協(xié)程的那些事兒

Part 01進(jìn)程,線程到協(xié)程

眾所周知,計算機(jī)操作系統(tǒng)中有兩個常見的概念:進(jìn)程和線程。要講協(xié)程,我們先從這兩個基本概念入手。

? 進(jìn)程:操作系統(tǒng)中每一個獨(dú)立允許的程序,都會占有操作系統(tǒng)分配的資源,是資源分配的基本單位。進(jìn)程之間互不干涉,都只負(fù)責(zé)運(yùn)行自己的指令,這就是進(jìn)程。

? 線程:進(jìn)程中的一個實體,是被系統(tǒng)獨(dú)立調(diào)度和CPU分派資源的基本單位,線程自己不擁有系統(tǒng)資源,只擁有一些運(yùn)行時必不可少的資源,如自己的堆棧,程序計數(shù)器,寄存器數(shù)據(jù)等。一個進(jìn)程可以有多個線程,各個線程共享進(jìn)程所擁有的全部資源。

? 協(xié)程:協(xié)作的線程,也可以被稱作微線程,是一種用戶態(tài)的線程,協(xié)程的調(diào)度是由用戶主動完成的。代表了一種非搶占式的多任務(wù)并發(fā)的調(diào)度思想:協(xié)作式調(diào)度,即沒有優(yōu)先級高低的區(qū)分。

- 對比

1、從內(nèi)存占用,上下文切換內(nèi)容,上下文切換過程等角度進(jìn)行詳細(xì)對比。

8dc84184-bb65-11ee-8b88-92fbcf53809c.png

2、從包容關(guān)系上來說,一個進(jìn)程至少包含一個線程,一個線程里面有0個或者多個協(xié)程,因此可歸納為如下圖:

8dec8972-bb65-11ee-8b88-92fbcf53809c.png

Part 02從異步編程說起

異步編程,也可以叫做并發(fā)編程,并發(fā)不同于并行:并行是物理上并行,至少要有2個CPU,兩個線程同時運(yùn)行;而并發(fā)可以是單核,通過時間調(diào)度算法實現(xiàn)多任務(wù)調(diào)度,給人感覺是同時運(yùn)行,實際上某一時刻只有一個線程在運(yùn)行。異步編程能有效避免主線程被阻塞,特別是對于前端來說,如果主線程被阻塞,會導(dǎo)致APP無響應(yīng)。常見的異步編程有:多線程,回調(diào),Promise,響應(yīng)式編程以及協(xié)程。

- 多線程

以發(fā)微博來舉例,發(fā)布操作可以簡單歸結(jié)為如下三個操作:

1、獲取用戶簽名數(shù)據(jù)prepareSubmit

2、攜帶簽名數(shù)據(jù)進(jìn)行微博發(fā)布內(nèi)容提交請求postSubmit

3、處理請求,響應(yīng)結(jié)果processPost

最開始我們可能只有10個用戶,只需要啟動10個線程去操作,但是隨著用戶數(shù)增加到1000個,10000個,這個時候如果啟動10000個線程,由于每個線程至少會占用4M,10000個線程會占用39G的內(nèi)存,對服務(wù)器的性能要求太高了,并且線程之間的切換也會占用大量的系統(tǒng)時間。因此這種方式只適用于線程之間沒有競爭關(guān)系,占用內(nèi)存資源少,切對時延不敏感的情況。

8e0734f2-bb65-11ee-8b88-92fbcf53809c.png

- 回調(diào)

如果用異步回調(diào)的等方式解決上面發(fā)微博的問題,我們可以用如下代碼來解決,這種方式簡單易懂,使用范圍也很廣,幾乎所有的異步框架都用到了回調(diào)。但是也有很明顯的問題:

1、如果步驟很多就會出現(xiàn)嵌套地獄

2、對于異常的情況很難處理和傳遞

3、如果某一個步驟要等多個回調(diào)完成之后再進(jìn)行收口操作,也很困難

8e1c9b4e-bb65-11ee-8b88-92fbcf53809c.png

- Promise

Promise是說對于一個耗時比較久的操作,程序給你一個承諾,保證不久之后會把結(jié)果告知你。它采用了鏈?zhǔn)骄幊棠P停喕嘶卣{(diào)的異步操作,解決了嵌套地獄的問題,Promise有以下幾種狀態(tài):

待定(pending): 初始狀態(tài),既沒有被兌現(xiàn),也沒有被拒絕。

兌現(xiàn)(fulfilled): 操作成功完成。

拒絕(rejected): 操作失敗。

發(fā)微博問題使用promise來解決如圖,必須等前置條件兌現(xiàn)之后才往后。

8e28f3c6-bb65-11ee-8b88-92fbcf53809c.png

Promise存在如下問題:

1、每一步的返回值類型都必須是 Promise,不能是實際的數(shù)據(jù)類型

2、錯誤處理變得復(fù)雜,不同階段產(chǎn)生的錯誤很難一路傳遞下去

3、不同階段之間共享數(shù)據(jù)困難

- 響應(yīng)式編程

響應(yīng)式編程(Reactive Extension簡稱Rx)的核心是將一切當(dāng)作數(shù)據(jù)流,關(guān)注數(shù)據(jù)流的變換和流轉(zhuǎn),描述數(shù)據(jù)輸入與輸出之間的關(guān)系,會實現(xiàn)數(shù)量眾多的擴(kuò)展函數(shù),這些函數(shù)只對輸入和輸出負(fù)責(zé),因此可以很輕松的將函數(shù)分發(fā)到其他線程上實現(xiàn)異步調(diào)用。但Rx調(diào)試比較困難,學(xué)習(xí)成本較高,維護(hù)也不易。

- 協(xié)程

考慮到大部分互聯(lián)網(wǎng)請求都是IO密集型而不是CPU密集型,基本的流程都是:請求-少量計算-調(diào)用公共服務(wù)-大量讀寫數(shù)據(jù)庫-返回數(shù)據(jù)。因此IO密集型很容易發(fā)生讀寫阻塞,此時會進(jìn)行線程切換,執(zhí)行其他線程。但線程是寶貴的計算資源,因此我們希望線程不要阻塞,一直跑,不要切換上下文。針對這種需求,協(xié)程的優(yōu)勢就出來了。協(xié)程執(zhí)行如圖:

8e497d26-bb65-11ee-8b88-92fbcf53809c.png

★ 優(yōu)點(diǎn)

1)協(xié)程的創(chuàng)建,銷毀和調(diào)度都發(fā)生在用戶態(tài),避免CPU頻繁切換帶來的資源浪費(fèi)

2)內(nèi)存占用小,可以輕松創(chuàng)建幾十萬的協(xié)程

3)可讀性高,易維護(hù),代碼基本等同于同步

4)通過結(jié)構(gòu)化并發(fā)限制控制域,減少內(nèi)存泄漏

Part 03種類劃分

- 按照調(diào)用棧分類

協(xié)程最關(guān)鍵的步驟就是暫停代碼和恢復(fù)代碼執(zhí)行,實現(xiàn)方法主要基于棧和狀態(tài)機(jī)&閉包兩種。通過區(qū)分執(zhí)行協(xié)程的時候是否可以在任意嵌套函數(shù)中被掛起,可以分為有棧協(xié)程和無棧協(xié)程,有棧協(xié)程可以被掛起,無棧協(xié)程不能被掛起。先看正常的函數(shù)棧操作:

8e64ef34-bb65-11ee-8b88-92fbcf53809c.png

有棧協(xié)程

協(xié)程實現(xiàn)的關(guān)鍵點(diǎn)就是如何保存、恢復(fù)和切換上下文,如果將一個函數(shù)當(dāng)作協(xié)程,當(dāng)有棧協(xié)程對函數(shù)的上下文進(jìn)行保存,恢復(fù)和切換操作時,會對這個函數(shù)及其嵌套函數(shù),棧針存儲的值,寄存器存儲的值進(jìn)行快照操作,之后只需要對快照做,恢復(fù)和切換。

無棧協(xié)程

相比于有棧協(xié)程,無棧協(xié)程在不改變調(diào)用棧的情況下采用了類似狀態(tài)機(jī)和閉包的方式來存儲暫停點(diǎn)的代碼信息。在不改變函數(shù)調(diào)用棧的情況下,我們也不可能在任意一個嵌套函數(shù)中掛起協(xié)程,這也是無棧協(xié)程的特點(diǎn),同時由于不需要切換棧幀,無棧協(xié)程的性能比有棧協(xié)程還要高一點(diǎn)。

- 按照調(diào)度方式分類

協(xié)程的暫停和恢復(fù)涉及到控制權(quán)的轉(zhuǎn)移,可以分為非對稱協(xié)程和對稱協(xié)程。

非對稱協(xié)程

非對稱協(xié)程通過暫停和繼續(xù)兩個指令進(jìn)行控制權(quán)轉(zhuǎn)移,暫停之后控制權(quán)就會轉(zhuǎn)移給繼續(xù)指令所在的協(xié)程,因此控制權(quán)的轉(zhuǎn)移存在較弱的調(diào)用方和被調(diào)用方的關(guān)系。

對稱協(xié)程

對稱協(xié)程只有一個繼續(xù)指令,各協(xié)程之間地位是平等的,繼續(xù)指令執(zhí)行之后,控制權(quán)就會在多個協(xié)程之間流轉(zhuǎn)。

Part 04總結(jié)

在高并發(fā)、高請求當(dāng)?shù)赖慕裉欤侠砝脜f(xié)程勢必會提升我們的系統(tǒng)性能和用戶體驗。當(dāng)我們的業(yè)務(wù)操作或者網(wǎng)絡(luò)請求面臨大量IO時,我們可以考慮采用協(xié)程替換線程,能夠幫助我們的應(yīng)用降低系統(tǒng)內(nèi)存占用,同時也減少了系統(tǒng)切換開銷,提升系統(tǒng)性能。然而協(xié)程雖然很強(qiáng)大,但是也不要過度使用,協(xié)程只有和異步IO結(jié)合起來才能發(fā)揮出最大的威力。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10804

    瀏覽量

    210828
  • 操作系統(tǒng)
    +關(guān)注

    關(guān)注

    37

    文章

    6684

    瀏覽量

    123140
  • 編程
    +關(guān)注

    關(guān)注

    88

    文章

    3565

    瀏覽量

    93536
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    503

    瀏覽量

    19634

原文標(biāo)題:關(guān)于協(xié)程,你了解多少?

文章出處:【微信號:5G通信,微信公眾號:5G通信】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    電源選型的那些事兒

    電路教程相關(guān)知識的資料,關(guān)于電源選型的那些事兒
    發(fā)表于 10-10 14:34 ?0次下載

    Linux的那些事兒之我是Sysfs

    Linux的那些事兒之我是Sysfs
    發(fā)表于 10-29 09:28 ?5次下載
    Linux的<b class='flag-5'>那些</b><b class='flag-5'>事兒</b>之我是Sysfs

    Linux的那些事兒之我是SCSI硬盤

    Linux的那些事兒之我是SCSI硬盤
    發(fā)表于 10-29 09:32 ?19次下載
    Linux的<b class='flag-5'>那些</b><b class='flag-5'>事兒</b>之我是SCSI硬盤

    Linux的那些事兒之我是Block層

    Linux的那些事兒之我是Block層
    發(fā)表于 10-29 09:43 ?9次下載
    Linux的<b class='flag-5'>那些</b><b class='flag-5'>事兒</b>之我是Block層

    分析電路:談?wù)?/b>反射的那些事兒資料下載

    電子發(fā)燒友網(wǎng)為你提供分析電路:談?wù)?/b>反射的那些事兒資料下載的電子資料下載,更有其他相關(guān)的電路圖、源代碼、課件教程、中文資料、英文資料、參考設(shè)計、用戶指南、解決方案等資料,希望可以幫助到廣大的電子工程師們。
    發(fā)表于 04-03 08:48 ?5次下載
    分析電路:<b class='flag-5'>談?wù)?/b>反射的<b class='flag-5'>那些</b><b class='flag-5'>事兒</b>資料下載

    Python后端項目的協(xié)是什么

    最近公司 Python 后端項目進(jìn)行重構(gòu),整個后端邏輯基本都變更為采用“異步”協(xié)的方式實現(xiàn)??粗鴿M屏幕經(jīng)過 async await(協(xié)在 Python 中的實現(xiàn))修飾的代碼,我頓時
    的頭像 發(fā)表于 09-23 14:38 ?1297次閱讀

    Python協(xié)與JavaScript協(xié)的對比及經(jīng)驗技巧

    前言以前沒怎么接觸前端,對 JavaScript 的異步操作不了解,現(xiàn)在有了點(diǎn)了解。一查發(fā)現(xiàn) Python 和 JavaScript 的協(xié)發(fā)展史簡直就是一毛一樣!這里大致做下橫向?qū)Ρ群涂偨Y(jié),便于
    的頭像 發(fā)表于 10-20 14:30 ?1869次閱讀

    使用channel控制協(xié)數(shù)量

    goroutine 是輕量級線程,調(diào)度由 Go 運(yùn)行時進(jìn)行管理的。Go 語言的并發(fā)控制主要使用關(guān)鍵字 go 開啟協(xié) goroutine。Go 協(xié)(Goroutine)之間通過信道(
    的頭像 發(fā)表于 09-19 15:06 ?1102次閱讀

    詳解Linux線程、線程與異步編程、協(xié)與異步

    協(xié)不是系統(tǒng)級線程,很多時候協(xié)被稱為“輕量級線程”、“微線程”、“纖(fiber)”等。簡單來說可以認(rèn)為
    的頭像 發(fā)表于 03-16 15:49 ?932次閱讀

    協(xié)的概念及協(xié)的掛起函數(shù)介紹

    協(xié)是一種輕量級的線程,它可以在單個線程中實現(xiàn)并發(fā)執(zhí)行。與線程不同,協(xié)不需要操作系統(tǒng)的上下文切換,因此可以更高效地使用系統(tǒng)資源。Kotlin 協(xié)
    的頭像 發(fā)表于 04-19 10:20 ?854次閱讀

    Kotlin協(xié)實戰(zhàn)進(jìn)階之筑基篇1

    。 Android 中的每個應(yīng)用都會運(yùn)行一個主線程,它主要是用來處理 UI,如果主線程上需要處理的任務(wù)太多,應(yīng)用就感覺被卡主一樣影響用戶體驗,得讓那些耗時的任務(wù)不阻塞主線程的運(yùn)行。要做到處理網(wǎng)絡(luò)請求不會阻塞主線程,一個常用的做法就是使用回調(diào),另一種是使用協(xié)
    的頭像 發(fā)表于 05-30 16:24 ?667次閱讀
    Kotlin<b class='flag-5'>協(xié)</b><b class='flag-5'>程</b>實戰(zhàn)進(jìn)階之筑基篇1

    Kotlin協(xié)實戰(zhàn)進(jìn)階之筑基篇3

    。 Android 中的每個應(yīng)用都會運(yùn)行一個主線程,它主要是用來處理 UI,如果主線程上需要處理的任務(wù)太多,應(yīng)用就感覺被卡主一樣影響用戶體驗,得讓那些耗時的任務(wù)不阻塞主線程的運(yùn)行。要做到處理網(wǎng)絡(luò)請求不會阻塞主線程,一個常用的做法就是使用回調(diào),另一種是使用協(xié)
    的頭像 發(fā)表于 05-30 16:26 ?654次閱讀

    FreeRTOS任務(wù)與協(xié)介紹

    。 協(xié)是為那些資源很少的 MCU 準(zhǔn)備的,其開銷很小,但是 FreeRTOS 官方已經(jīng)不打算再更新協(xié)了。 任務(wù)特性: 1、簡單。 2、沒
    的頭像 發(fā)表于 09-28 11:02 ?934次閱讀

    協(xié)的實現(xiàn)與原理

    前言 協(xié)這個概念很久了,好多程序員是實現(xiàn)過這個組件的,網(wǎng)上關(guān)于協(xié)的文章,博客,論壇都是汗牛充棟,在知乎,github上面也有很多大牛寫了關(guān)于協(xié)
    的頭像 發(fā)表于 11-10 10:57 ?401次閱讀

    Linux線程、線程與異步編程、協(xié)與異步介紹

    協(xié)不是系統(tǒng)級線程,很多時候協(xié)被稱為“輕量級線程”、“微線程”、“纖(fiber)”等。簡單來說可以認(rèn)為
    的頭像 發(fā)表于 11-11 11:35 ?1012次閱讀
    Linux線程、線程與異步編程、<b class='flag-5'>協(xié)</b><b class='flag-5'>程</b>與異步介紹