999精品在线视频,手机成人午夜在线视频,久久不卡国产精品无码,中日无码在线观看,成人av手机在线观看,日韩精品亚洲一区中文字幕,亚洲av无码人妻,四虎国产在线观看 ?

并發編程關鍵模型及語言實現

2021-08-06 08:25:48高永強
現代計算機 2021年18期
關鍵詞:進程語言模型

高永強

(武警工程大學信息工程學院,西安710086)

0 引言

傳統并發編程一般采用多進程或者多線程的方式,需要考慮數據競爭、同步互斥、死鎖等等問題,使開發并發程序尤其是大型服務器程序的難度大大加大。大量的進程或線程創建不僅會占用大量內存,而且隨著線程數量的增多,多線程之間切換的開銷是不容忽視的,會浪費大量CPU時間在調度上[1]。在當今互聯網高并發場景下,迫切需要新的并發編程方式來滿足高并發的需要,同時降低并發程序的開發難度。

并發編程最大的困難就在與對共享資源的競爭,CSP(Communicating Sequential Process,通訊順序進程)和Actor模型都是基于消息傳遞的并發編程模型,它們的并發體之間不共享內存,由此可以在業務代碼層面實現無鎖并發。同時,CSP模型、Actor模型和協程模型中并發體的調度和切換發生在用戶態,大幅降低了切換開銷。

1 CSP模型

1.1 CSP模型基本概念

CSP是貝爾實驗室的Tony Hoare在1978年提出的一種并發模型。CSP有著精確的數學模型,并實際應用在了Hoare參與設計的T9000通用計算機上。CSP模型中最重要的兩個概念是Process(進程)和Channel(通道)。這里的進程和傳統多進程編程中的進程有所區別,CSP中的進程是實際并發執行的實體,是一種運行在用戶態的用戶線程,其調度不是由操作系統來完成的,而是由編程語言的運行時進行調度。CSP中通道是第一類對象,兩個獨立的并發實體通過共享的通道進行通信。在Java、C++、或者Python等語言的多線程編程中,線程間通信都是通過共享內存的方式來進行的,在訪問共享數據時,必須通過互斥鎖或信號量等機制確保數據的一致性。不同于傳統的多線程通過共享內存來通信,CSP講究的是“以通信的方式來共享內存”。在CSP模型中,程序就是一組無共享狀態進程的并行組合,進程間的通信和同步是通過Channel完成的。Process和Channel之間的關系如圖1所示。

圖1 Process和Channel之間的關系

1.2 CSP模型在Go語言中的實現

Go語言是為并發而生的語言,Go語言是為數不多的在語言層面實現并發的語言。Go語言強大的并發編程能力,使其在微服務架構和云原生技術領域大放異彩,Docker、Kubernetes和etcd等軟件均是采用Go語言進行開發的[2]。Go語言中通過Goroutine(Go協程)與Channel實現了CSP模型中的核心概念Process和Channel。Process在go語言上的表現就是Gorou?tine,它是實際并發執行的實體,每個實體之間是通過Channel通訊來實現數據共享。

(1)Goroutine的特點

不同于Python基于進程的并發模型,以及C++、Java等基于線程的并發模型,Go語言采用輕量級的Goroutine來實現并發。Goroutine是Go語言中并發的執行單位,通過Go關鍵字可以簡單而快速地創建一個Goroutine。與線程相比,Goroutine具有以下特點:

●用戶態。Goroutine處于用戶態,由Go語言調度器進行調度,避免了內核態和用戶態的切換導致的成本。Goroutine之間切換的開銷要比線程切換的開銷小得多,一個Go語言程序可以輕而易舉地創建成千上萬個Goroutine,而操作系統能夠創建的線程數量要少得多。

●輕量級。在一般的操作系統中,線程棧的大小是固定的且在運行過程中線程棧的大小不能伸縮,例如Linux系統默認線程棧大小是2MB。Goroutine默認棧要比線程棧小很多,一個Goroutine只占幾KB,并且Goroutine的棧是可伸縮的。

●通信靈活。Goroutine既可以通過共享內存進行通信,也可以通過Channel進行通信,給并發編程帶來了較大的靈活性。

(2)Goroutine的調度

Goroutine處于用戶態,最終要在操作系統線程上執行,Go語言調度器負責將多個Goroutine復用到線程上。調度器是線程和Goroutine的中間層,通過調度器的調度,每一個內核線程都能夠執行多個Goroutine,并且在Goroutine進行一些I/O操作時及時切換,提高線程的利用率。Go目前使用的調度器是基于GMP模型重新設計的,其中G表示Goroutine,它是一個待執行的任務;M表示操作系統的線程,它由操作系統的調度器調度和管理;P表示處理器,它可以被看做運行在線程上的本地調度器。

(3)Go Channel

(1)給出輸入信號x(t),設置迭代次數,通常情況下,迭代次數越高,分解越精確,但是同時所花時間也越長。將重建信號初始化置零。

作為Go核心的數據結構和Goroutine之間的通信方式,Channel是支撐Go語言高性能并發編程模型的重要結構。在很多主流的編程語言中,多個線程一般通過共享內存方式進行通信和傳遞數據。雖然在Go語言中也能使用共享內存加互斥鎖進行通信,但推薦的方式是通過Channel進行Goroutine之間的通信。“不要通過共享內存來通信,要通過通信來共享內存”是Go語言重要的設計哲學。

Go語言中的Channel是一種隊列式的數據結構,遵循先入先出的規則。Go中Channel的容量可以為0,容量為0的Channel被稱為無緩沖的Channel,容量大于0的Channel被稱為有緩沖的Channel。對于無緩沖Channel,如果向Channel發送數據的Goroutine先被調用,則該Goroutine將被掛起直到接收數據的Gorou?tine被調用。同樣,如果接收數據的Goroutine先被調用,它將被掛起直到發送數據的Goroutine被調用。有緩沖的Channel和阻塞隊列非常類似,如果Channel已滿,那么向Channel發送數據的Goroutine將被掛起。反之,如果Channel為空,從Channel接收數據的Gor?outine將被掛起。Channel支持創建、接收、發送和關閉四個操作。與BlockingQueue不同的是,Channel可以被關閉,發送者關閉通道來表明沒有更多的元素將會進入通道。Go從語言層面保證同一個時間只有一個Goroutine能夠訪問Channel里面的數據。基于這些特性,使用Channel可以輕松實現Goroutine之間的同步和互斥。

2 Actor模型

2.1 Actor模型基本概念

Actor模型是一種并發計算模型,其中的Actor是計算的基本單位,1973年Carl Hewitt在論文A Universal Modular Actor Formalism for Artificial Intelligence中首次提出Actor模型[3]。Actor模型由一個個稱為Actor的執行體和Mailbox(郵箱)組成。在Actor理論中,一切都被認為是Actor,一個Actor實例是執行計算的最小單元,擁有自己的狀態和行為,它能接收一個消息并且基于消息內容執行計算任務。

Actor與Actor之間只能通過消息進行通信,一個Actor可以發送消息給其他Actor,也可以從其他Actor接收消息,如圖2所示。Actor模型內部的狀態由自己的行為維護,外部線程不能直接調用對象的行為,保證了Actor內部數據只有被自己修改。Actor的一大重要特征在于Actor之間相互隔離,它們并不互相共享內存,一個Actor能維持一個私有的狀態。由于Actor之間沒有共享數據,所以可以輕松實現無鎖并發。

圖2 Actor之間的通信方式

每個Actor都有一個屬于自己的信箱。Actor的信箱類似一個隊列,發送到Actor的消息依次存入目標Actor的信箱中等待處理。每個Actor是串行處理信箱中的消息的,這樣在Actor內部保證了不會出現并發安全問題。當一個Actor接收到消息后,它能做如下三件事中的一件:創建其他Actor;向其他Actor發送消息;指定當前的Actor如何處理下一個消息。這樣的設計解耦了Actor之間的關系,且發送消息時不會被阻塞。雖然所有Actor可以同時運行,但它們都按照信箱接收消息的順序來依次處理消息,且僅在當前消息處理完成后才會處理下一個消息。

2.2 Actor模型在Scala語言中的實現

Scala語言的Akka庫實現了Actor模型,其借鑒了Erlang的Actor模型實現,同時又引入了許多新的特性,為并發編程提供了強大的工具[4]。Akka是一款優秀的分布式并發框架,由Scala語言開發,運行于Java虛擬機之上,同時支持使用Scala、Java和Kotlin等基于JVM的語言進行編程。在Scala語言中仍然可以使用Java線程,但是使用Akka中的Actor模型是更好的選擇。Akka中的Actor是一個比線程更高層的抽象,最終是跑在Java的線程中的,多個Actor在底層可以共享一個線程。使用Akka進行并發編程可以不用擔心底層線程、鎖和共享數據沖突等傳統多線程編程面臨的問題。Akka提供了豐富的組件,比如郵箱、路由組件、持久化組件等,在底層對分布式和并行模式進行了高度且統一的抽象,使用很少的代碼就可以實現一個完整的高并發分布式應用[5]。

(1)Akka中Mailbox的并發安全機制

對于Mailbox存在兩個操作,一個是向Mailbox中寫入消息,一個是從Mailbox中讀取消息,因此可能會出現一條消息在被寫入Mailbox中還沒結束的時候,就被Actor讀取走的情況,這就會引發并發安全問題。所以Mailbox必須保證消息完整地寫入后才能被接收處理,即Mailbox必須是并發訪問安全的。Mailbox的底層數據結構是一個線程安全的存儲消息的隊列,Scala標準庫中的LinkedBlockingDeque和ConcurrentLinked?Queue等線程安全隊列均可以作為Mailbox的底層基礎結構。但Akka沒有采用這種方案,而是實現了一個AbstractNodeQueue數據結構,這種結構是一個功能更加明確的隊列,專門為Mailbox的需求所設計,在兼顧較高性能的同時,保證了上層Mailbox的并發訪問安全。

(2)Actor之間的消息傳遞

在Akka中,可以使用tell和ask兩種方式向Actor發送消息,它們都以異步的方式發送消息,不同的是,前者發完后立即返回,而后者會返回一個Future對象,假如在設置的時間內沒有得到返回結果,消息的發送方會收到一個超時異常。

(3)Akka中Actor的層級關系

如圖3所示,Actor系統從上到下有嚴格的層級關系。與父進程可以創建子進程類似,一個Actor也可以創建多個子Actor,最終形成一種樹形結構。當子Ac?tor在處理消息時發生了異常,父Actor可以通過預先設定的動作進行處理,處理方式有:恢復子Actor、重啟子Actor、停止子Actor、向上級Actor報告,這樣的處理方式被稱為“父監督”模式。

圖3 Actor系統的樹形結構

3 協程

3.1 協程基本概念

協程并不是一個新概念,早在1963年協程這一概念就被提出[6-7],并在古老的Simula和Modula-2語言中得到了實現。但長期以來,協程這一概念并沒有引起足夠的重視,主流編程語言也鮮見對于協程的支持。隨著云計算、大數據時代的到來,如何提高軟件的并發能力以充分利用硬件性能成為重要的研究課題。在高并發條件下,協程具有上下文切換開銷小和資源利用率高的特性而重新得到開發人員的重視。隨著Lua、Golang、Kotlin等主流語言對于協程的支持越來越完善,協程重新登上歷史舞臺。

協程又稱纖程,是一種用戶級線程,操作系統不知道協程的存在。協程與進程或線程最直接的區別表現在,協程是編譯器層面的概念,而進程與線程則是操作系統層面的概念。協程能夠被掛起,稍后再在掛起的位置恢復執行,其掛起和恢復是由開發者的程序邏輯自己控制的,通過主動掛起讓出運行權可以實現協程之間的協作。和進程與線程相比,協程具有以下幾個優勢。其一,創建協程消耗的系統資源更小。協程的棧空間可以根據需要進行擴容和縮容,最小為內存頁長,而線程的??臻g大小一般為MB級別。其二,協程之間的切換代價更小。協程的調度發生在用戶態,避免了線程上下文切換帶來的開銷。其三,協程可以實現無鎖編程。

2004年Lua語言之父Roberto Ierusalimschy在其發表的論文Revisiting Coroutines中,根據協程的實現方式的差異對協程進行了分類[8]。

按是否開辟調用棧,將協程分為有棧協程和無棧協程。有棧協程具有自己的調用棧,協程掛起時其中斷狀態會保存在調用棧中。其優點是可以在任意函數調用層級的任意位置掛起,并轉移調度權。Lua語言中的協程是這種實現方式的典型代表。與之相對應,無棧協程沒有自己的調用棧,掛起點的狀態則是通過狀態機或者閉包等語法來實現。其優點是內存開銷較小,Python語言中的Generator是這種協程的典型代表。

按調度方式的不同,將協程分為對稱協程和非對稱協程。對稱協程中每一個協程都是地位平等且相互獨立的,調度權可以在任意協程之間轉移。上文中提到的Go語言中的Goroutine是這種實現方式的典型代表,Goroutine可以通過對Channel的讀寫實現控制權的自由轉移。而非對稱協程在掛起后,只能將調度權出讓給它的調用者,即協程之間存在調用與被調用的關系。Lua語言中的協程是典型的非對稱協程,當前協程調用yield后總是將調度權讓給之前調用它的協程。

協程是用戶態的概念,其最終還是要運行在操作系統線程上,根據協程和線程的對應關系,可以分為多對一、一對一和多對多三類。多對一是指多個協程對應一個底層線程,只要內存足夠,一個線程中可以有任意多個協程,多個協程共享該線程分配到的計算機資源。其優點是協程切換時不會進入內核態,從而減少切換開銷。一對一是指協程和底層線程是一一對應的關系,這種方式可以充分利用多核性能,但是協程切換會進入內核態,開銷較大。多對多是指協程和底層線程沒有特定對應關系。某一協程在某時刻可以在線程A執行,一段時間之后又可能在線程B上執行。這種方式融合了前兩種方式的優點,但是實現較為困難。

3.2 協程在Kotlin語言中的實現

Kotlin是一種運行在Java虛擬機上的靜態類型語言,由JetBrain公司設計開發。Kotlin目前是JVM語言家族中的重要成員之一,它的出現充分彌補了Java缺乏現代化編程語言特性的缺憾[9]。在Google I/O 2017大會上,Google宣布Kotlin成為Android官方開放語言。

Kotlin是少有的幾門從語法和標準庫兩個層面對協程提供支持的編程語言。在語法層面,被suspend關鍵字修飾的函數稱為掛起函數,Kotlin協程的掛起和恢復本質上就是掛起函數的掛起和恢復[10]。掛起函數只能在協程體內或其他掛起函數內調用,不能被普通函數調用。同時,除了標準庫以外,Kotlin官方還推出了面向生產環境的kotlin.coroutines框架,該框架提供了豐富的編程接口和組件來支撐生產環境中異步高并發程序的設計和實現,例如熱數據通道Channel、冷數據流Flow等高級數據結構。

Kotlin語言除了可以編譯為字節碼運行在Java虛擬機上以外,還可以通過LLVM編譯鏈工具最終編譯成機器碼,這一多平臺特性大大擴展了協程的應用場景。目前Kotlin對于協程的支持正在不斷完善,快速迭代,相信不久的將來,必將給開發者帶來開發體驗和開發效率上的全方位提升。

4 模型之間的比較

如表1所示,協程、CSP模型和Actor模型與傳統的多進程/多線程相比,具有通信方式靈活、并發度高、調用棧較小和開銷低的特點。

表1 并發編程模型之間的比較

進程、線程和協程的異同點表現在以下幾個方面:每個進程擁有獨立的堆和棧,進程之間既不共享堆,也不共享棧,其調度由操作系統負責。每個線程擁有獨立的棧和共享的堆,線程之間不共享棧,但同一進程內的線程共享堆空間,其調度亦由操作系統負責。協程,也是共享堆,不共享棧,但協程不是操作系統調度單元,而是由用戶調度。

CSP模式和Actor模式有許多共同點,兩者都通過消息傳遞的方式來避免共享內存引發的數據競爭問題,Actor模型中的Mailbox與CSP模型中的Channel都滿足先進先出的特性。但CSP與Actor有以下幾點比較大的區別:

(1)Actor模型中的Mailbox對程序員是透明的,Mailbox明確歸屬于某一個特定的Actor,是Actor模型的內部機制。CSP模型中的Channel對于程序員來說是可見的,必須由程序員手動創建。

(2)Actor模型中發送消息是非阻塞的。相反,CSP中的Channel是一個阻塞隊列,當Channel已滿時,繼續向Channel發送數據,會導致發送消息的Goroutine被掛起。當Channel為空時,繼續從Channel讀取數據,會導致接收消息的Goroutine被掛起。

(3)Actor模型理論上不保證消息百分比送達,而Go實現的CSP模型中,能保證消息百分百送達。

(4)Actor模型中,Actor與Mailbox是一對一的關系,每個Actor有且只有一個Mailbox,而在CSP中Channel和Process之間沒有從屬關系,兩者之間是多對多的關系,Process可以訂閱任意個Channel,一個Channel也可以被多個Process操作。

5 結語

隨著多核CPU的高速發展和大規模分布式應用的逐漸普及,提高軟件系統的并發能力是當前亟待解決的問題,傳統的多進程和多線程編程方式無法較好地滿足快速構建高可用、高性能和高并發的分布式應用的要求。在當今互聯網高并發場景下,迫切需要新的并發編程方式來滿足高并發的需要,同時降低并發程序的開發難度。使用傳統并發編程方式寫出一個高性能并且可擴展的并發程序是相當困難的。高并發程序設計既是一個重點,也是一個難點。

提高系統的并發能力主要有垂直擴展和水平擴展兩種方式,垂直擴展通過提升單機性能來提高系統的并發性能,水平擴展則通過增加服務器數量提升并發性。未來分布式高并發應用場景的不斷多樣化,提高系統的并發性必將朝著垂直擴展和水平擴展相結合的方向發展。CSP、Actor和協程等并發計算模型是進行垂直擴展,提高系統并發能力的重要手段,隨著編程語言對并發計算模型的支持不斷完善,新的編程方式必將大大提升應用開發效率。

猜你喜歡
進程語言模型
一半模型
重要模型『一線三等角』
重尾非線性自回歸模型自加權M-估計的漸近分布
語言是刀
文苑(2020年4期)2020-05-30 12:35:30
債券市場對外開放的進程與展望
中國外匯(2019年20期)2019-11-25 09:54:58
讓語言描寫搖曳多姿
累積動態分析下的同聲傳譯語言壓縮
3D打印中的模型分割與打包
我有我語言
社會進程中的新聞學探尋
民主與科學(2014年3期)2014-02-28 11:23:03
主站蜘蛛池模板: 国产三级毛片| 777午夜精品电影免费看| 五月婷婷丁香综合| 亚洲av无码成人专区| 啪啪免费视频一区二区| 97超碰精品成人国产| 免费A级毛片无码免费视频| 欧美精品在线视频观看| 欧美一区国产| 欧美日韩一区二区在线免费观看| 呦女亚洲一区精品| 伊人天堂网| 在线国产毛片手机小视频| 激情影院内射美女| 91www在线观看| 亚洲男人的天堂网| 国产三区二区| 在线观看国产精品第一区免费| 中文字幕av无码不卡免费| 亚洲精品午夜天堂网页| 91视频精品| 97超级碰碰碰碰精品| 精品久久国产综合精麻豆| a免费毛片在线播放| 欧洲熟妇精品视频| 另类欧美日韩| 国产精品永久不卡免费视频 | 精品第一国产综合精品Aⅴ| 国产精品久久久久久久久kt| 日本成人一区| 人妻无码AⅤ中文字| 久久久噜噜噜| 久久国语对白| 精品国产成人av免费| 日韩专区欧美| 四虎精品黑人视频| 在线不卡免费视频| 在线观看亚洲精品福利片| 视频在线观看一区二区| 亚洲香蕉伊综合在人在线| 丝袜高跟美脚国产1区| 国产女人在线观看| 国产91特黄特色A级毛片| 无码一区中文字幕| 欧美在线三级| 一级黄色片网| 高清乱码精品福利在线视频| 五月天综合婷婷| 国产丝袜丝视频在线观看| 午夜a级毛片| 精品久久人人爽人人玩人人妻| 精品国产一区91在线| 国产三级毛片| 久996视频精品免费观看| 国产成人综合亚洲网址| 欧美成人在线免费| 久久久无码人妻精品无码| 97国产精品视频自在拍| 国产精品自在在线午夜区app| 国产96在线 | 国产麻豆精品久久一二三| 亚洲欧美精品在线| 精品久久久久无码| 99视频在线精品免费观看6| 久久国产V一级毛多内射| 激情无码字幕综合| 在线观看精品国产入口| 日韩精品久久无码中文字幕色欲| 国产网友愉拍精品视频| 91麻豆精品视频| 国产女人爽到高潮的免费视频| 成人福利在线观看| 国产无人区一区二区三区| 国产91高清视频| 成人午夜天| 国产91九色在线播放| 中国一级特黄视频| 国产一级二级三级毛片| 国产日韩丝袜一二三区| 一区二区偷拍美女撒尿视频| 亚洲成aⅴ人在线观看| 一区二区三区精品视频在线观看|