Coroutine技術學習研究

      網友投稿 1072 2022-05-30

      Coroutines是一種計算機程序組件,它通過允許暫停執行和恢復執行來實現非搶先性多任務的子程序。Coroutines非常適合實現熱門的程序任務組件,如合作任務、異常、事件循環、迭代器、無限列表和管道。

      根據Donald Knuth的說法,Melvin Conway在1958年創造了coroutine這個術語,當時他將其應用于匯編程序的構建。

      1??????與子程序的比較

      子程序是coroutine的特例,當子程序被調用時,執行開始,子程序一旦退出,就結束了;一個子程序的實例只返回一次,在調用之間不保持狀態。與此相反,coroutine可以通過調用其他coroutine來退出,這些coroutine以后可能會返回到原coroutine中被調用的點;從coroutine的角度來看,它不是退出,而是調用另一個coroutine,因此,一個coroutine實例保持狀態,在調用之間變化;一個給定的coroutine可以同時有多個實例。通過對另一個coroutine的?"yielding"來調用另一個coroutine和簡單地調用另一個coroutine(那么,也會回到原點)的區別在于,兩個相互屈服的coroutine之間不是調用者-被調用者的關系,而是對稱的關系。

      任何子程序都可以翻譯成一個不調用yield的coroutine。

      下面是一個簡單的例子,說明例程如何工作。假設你有一個消費者-生產者的關系,其中一個例程創建項目并將它們添加到隊列中,另一個例程從隊列中刪除項目并使用它們。為了提高效率,您希望同時添加和刪除多個項目。代碼可能是這樣的:

      var?q?:=?new?queue

      coroutine?produce

      loop

      while?q?is?not?full

      create?some?new?items

      add?the?items?to?q

      yield?to?consume

      coroutine?consume

      loop

      while?q?is?not?empty

      remove?some?items?from?q

      use?the?items

      yield?to?produce

      在使用yield命令將控制權交給另一個coroutine之前,隊列已經被完全填滿或清空。進一步的coroutine調用就在yield之后開始,在外層coroutine循環中。

      雖然這個例子經常被用來介紹多線程,但并不需要為此而使用兩個線程:yield語句可以通過直接從一個例程跳轉到另一個例程來實現。

      2??????與Thread的比較

      Coroutine與線程非常相似。然而,coroutine是合作式多任務的,而線程通常是先發制人的多任務。這意味著,coroutine提供并發性,但不提供并行性。與線程相比,coroutine的優勢在于它們可以在硬實時環境中使用(在coroutine之間的切換不需要涉及任何系統調用或任何阻塞調用),不需要同步基元(如mutexes、semaphores等)來保護關鍵部分,也不需要操作系統的支持。

      可以使用預先調度的線程來實現coroutine,這種方式對調用代碼是透明的,但會失去一些優勢(特別是適合硬實時操作和相對便宜的切換)。

      3??????與生成器的比較

      生成器,又稱semicoroutine,是coroutine的一個子集。具體來說,雖然兩者都可以多次yield,暫停執行,并允許在多個入口點重新進入,但它們的不同之處在于coroutine可以控制在yield后立即在哪里繼續執行,而生成器則不能,而是將控制權轉回生成器的調用者手中。?也就是說,由于生成器主要用于簡化迭代器的編寫,所以生成器中的屈服語句并不指定跳轉到哪個coroutine,而是將一個值傳回父例程。

      然而,仍然可以在生成器設施之上實現coroutines,借助一個頂層調度例程(本質上是一個蹦床),將控制權顯式地傳遞給由生成器傳回的令牌識別的子生成器。

      var?q?:=?new?queue

      generator?produce

      loop

      while?q?is?not?full

      create?some?new?items

      add?the?items?to?q

      yield?consume

      generator?consume

      loop

      while?q?is?not?empty

      remove?some?items?from?q

      use?the?items

      yield?produce

      subroutine?dispatcher

      var?d?:=?new?dictionary(generator?→?iterator)

      d[produce]?:=?start?produce

      d[consume]?:=?start?consume

      var?current?:=?produce

      loop

      current?:=?next?d[current]

      一些支持生成器但沒有本地生成器的語言(例如2.5之前的Python)的coroutines的實現使用了類似的模型。

      4??????與相互遞歸的比較

      在狀態機或并發中使用coroutine類似于使用尾部調用的相互遞歸,因為在這兩種情況下,控制權都會改變到一組例程中的不同的一個。然而,coroutine更靈活,通常更有效率。由于coroutine是yield而不是返回,然后是恢復執行而不是從頭開始,所以它們能夠保持狀態,包括變量(如closure)和執行點,而且yield不限于在尾部位置;相互遞歸的子例程必須使用共享變量或傳遞狀態作為參數。此外,子程序的每一次互遞歸調用都需要一個新的堆棧框架(除非實現尾部調用消除),而coroutine之間傳遞控制權則使用現有的上下文,只需通過跳轉即可實現。

      5??????常見用途

      Coroutine可以用來實現以下功能:

      1.?????????一個子程序內的狀態機,狀態由程序的當前進入/退出點決定;與使用goto相比,這可以使代碼更易讀,也可以通過尾部調用的相互遞歸實現。

      2.?????????并發的角色模型,例如在視頻游戲中。每個角色都有自己的程序(這又在邏輯上把代碼分開了),但他們自愿把控制權交給中央調度器,由中央調度器依次執行(這是一種合作多任務的形式)。

      3.?????????生成器,這些對于流--特別是輸入/輸出--和數據結構的通用遍歷是有用的。

      4.?????????通信順序進程,其中每個子進程是一個coroutine。通道輸入/輸出和阻塞操作產生coroutine,調度器在完成事件上解除阻塞。另外,在數據管道中,每個子進程可以是它后面的子進程的父進程(或前面的子進程,在這種情況下,模式可以表示為嵌套生成器)。

      5.?????????反向通信,通常用于數學軟件中,其中一個程序如求解器、積分評估器......需要使用過程進行計算,如評估方程或積分。

      6??????具有本地支持的編程語言

      Coroutines起源于一種匯編語言方法,但在一些高級編程語言中也得到了支持,早期的例子包括Simula、Smalltalk和Modula-2。早期的例子包括Simula、Smalltalk和Modula-2。最近的例子有Ruby、Lua、Julia和Go。

      1.?????????Aikido

      2.?????????AngelScript

      3.?????????Ballerina

      4.?????????BCPL

      5.?????????Pascal (Borland Turbo Pascal 7.0 with uThreads module)

      6.?????????BETA

      7.?????????BLISS

      8.?????????C++ (Since C++20)

      9.?????????C# (Since 2.0)

      10.?????ChucK

      11.?????CLU

      12.?????D

      13.?????Dynamic C

      14.?????Erlang

      15.?????F#

      16.?????Factor

      17.?????GameMonkey Script

      18.?????GDScript (Godot's scripting language)

      19.?????Go

      20.?????Haskell

      21.?????High Level Assembly

      22.?????Icon

      23.?????Io

      24.?????JavaScript (since 1.7, standardized in ECMAScript 6) ECMAScript 2017 also includes await support.

      25.?????Julia

      26.?????Kotlin (since 1.1)

      27.?????Limbo

      28.?????Lua[15]

      29.?????Lucid

      30.?????μC++

      31.?????MiniD

      32.?????Modula-2

      33.?????Nemerle

      34.?????Perl 5 (using the Coro module)

      35.?????PHP (with HipHop, native since PHP 5.5)

      36.?????Picolisp

      37.?????Prolog

      38.?????Python (since 2.5, with improved support since 3.3 and with explicit syntax since 3.5)

      39.?????Raku

      40.?????Ruby

      41.?????Sather

      42.?????Scheme

      43.?????Self

      44.?????Simula 67

      45.?????Smalltalk

      46.?????Squirrel

      47.?????Stackless Python

      48.?????SuperCollider

      49.?????Tcl (since 8.6)

      50.?????urbiscript

      由于連續性可以用來實現coroutine,所以支持連續性的編程語言也可以很容易地支持coroutine。

      7??????實現情況

      截止到2003年,許多最流行的編程語言,包括C語言及其衍生語言,在語言或其標準庫中都沒有對coroutine的直接支持。這在很大程度上是由于基于堆棧的子程序實現的限制)。一個例外是C++庫Boost.Context,它是boost庫的一部分,它支持ARM、MIPS、PowerPC、SPARC和POSIX、Mac OS X和Windows上的x86的上下文交換。Coroutine可以建立在Boost.Context基礎上。

      在一些情況下,coroutine是程序機制的自然需求實現,但很多時候不好用,典型的反應是使用Closure--一個帶有狀態變量(靜態變量,通常是布爾標志)的子程序,以在調用之間保持內部狀態,并將控制轉移到正確的點。代碼內部的條件導致在連續調用時,根據狀態變量的值執行不同的代碼路徑。另一種典型的應對措施是以大型復雜的switch語句的形式或通過goto語句,特別是計算的goto來實現一個顯式狀態機。這種實現被認為是難以理解和維護的,也是支持coroutine的一個動機。

      線程,以及在較小程度上的fiber,是目前主流編程環境中coroutine的替代方案。線程提供了管理同時執行的代碼片段的實時合作交互的設施。線程在支持C語言的環境中廣泛存在(許多其他現代語言也原生支持),為許多程序員所熟悉,而且通常都有良好的實現、良好的文檔和良好的支持。然而,由于它們解決的是一個龐大而困難的問題,它們包括許多強大而復雜的設施,并且具有相應的困難學習曲線。因此,當只需要一個coroutine時,使用線程可能是矯枉過正。

      線程和coroutine之間的一個重要區別是,線程通常是預先調度的,而coroutine則不是。因為線程可以在任何時刻重新調度,并且可以并發執行,所以使用線程的程序必須小心鎖定。相反,由于coroutine只能在程序中的特定點重新調度,并且不并發執行,使用coroutine的程序通常可以完全避免鎖定。這個特性也被引用為事件驅動或異步編程的一個好處)。

      由于fibers是合作調度的,因此它們為實現上述coroutines提供了一個理想的基礎,然而,與線程的支持相比,系統對fibers的支持往往是缺乏的。

      7.1????C中的實現

      為了實現通用的coroutine,必須獲得第二個調用棧,這是C語言不直接支持的功能。一個可靠的(盡管是特定于平臺的)方法是在初始創建coroutine的過程中使用少量的內聯匯編來顯式操作棧指針。這是Tom Duff在討論其與Protothreads使用的方法的相對優點時推薦的方法。在提供POSIX sigaltstack系統調用的平臺上,可以通過從信號處理程序內調用一個跳板函數來獲得第二個調用棧,在可移植的C語言中實現同樣的目標,但代價是一些額外的復雜性。符合POSIX或Single Unix Specification (SUSv3)的C庫提供了getcontext、setcontext、makecontext和swapcontext等例程,但這些函數在POSIX 1.2008中被宣布過時。

      一旦用上述方法之一獲得了第二個調用棧,就可以使用標準C庫中的setjmp和longjmp函數來實現coroutine之間的切換。這些函數分別保存和恢復堆棧指針、程序計數器、調用保存的寄存器以及ABI所要求的任何其他內部狀態,這樣,在屈服后返回到一個coroutine,就會恢復從函數調用返回時的所有狀態。極簡主義的實現,不依賴setjmp和longjmp函數,可以通過一個小的內聯程序塊來實現同樣的結果,這個內聯程序塊只交換堆棧指針和程序計數器,并(可以敞開了使用) clobbers所有其他寄存器。這可以顯著地提高速度,因為setjmp和longjmp必須根據ABI保守地存儲所有可能正在使用的寄存器,而clobber方法只允許編譯器存儲(通過溢出到堆棧),它知道實際正在使用的寄存器。

      除了上述一般方法外,還有一些人嘗試用子程序和宏的組合來近似C語言中的coroutines。Simon Tatham的貢獻基于Duff的裝置,是該流派的一個顯著的例子,也是Protothreads和類似實現的基礎。除了Duff的反對意見,Tatham自己的評論也對這種方法的局限性進行了坦率的評價。"據我所知,這是在嚴肅的生產代碼中見過的最糟糕的C語言黑客行為。"?這種近似方法的主要缺點是,由于沒有為每個coroutine維護一個單獨的堆棧框架,局部變量不能在函數的各次輸出中得到保存,不可能對函數有多個入口,而且只能從頂層例程中yield。

      7.2????C++中的實現

      1.?????????C++ coroutines TS (Technical Specification),是C++語言擴展的標準,用于類似coroutine行為的無堆棧子集,正在開發中。Visual C++和Clang已經支持std::experimental命名空間中的主要部分。

      2.?????????Boost.Coroutine--由Oliver Kowalke創建,是boost自1.53版本以來官方發布的可移植的coroutine庫,它依賴于Boost.Context,支持ARM、MIPS、PowerPC、SPARC和X86的POSIX、Mac OS X和Windows。

      3.?????????Boost.Coroutine2--也是由Oliver Kowalke創建的,是boost 1.59版本以來的一個現代化的便攜式coroutine庫。它利用了C++11的特性,但刪除了對對稱coroutine的支持。

      4.?????????Mordor--2010年,Mozy開源了一個實現coroutine的C++庫,重點是利用它們將異步I/O抽象成一個更熟悉的順序模型。

      5.?????????CO2 -?基于C++預處理器技巧的無堆棧的coroutine,提供了等待/收益模擬。

      6.?????????ScummVM - ScummVM項目基于Simon Tatham的文章實現了一個輕量級的無棧coroutine版本。

      7.?????????tonbit::coroutine - C++11單.h非對稱coroutine通過ucontext / fiber實現。

      8.?????????Coroutines于2017年5月登陸Clang,libc++的實現正在進行中?。

      9.?????????elle by Docker

      7.3????C#的實現

      1.?????????MindTouch Dream - MindTouch Dream REST框架提供了一個基于C# 2.0迭代器模式的coroutines實現。

      2.?????????Caliburn - WPF的Caliburn屏幕模式框架使用C# 2.0迭代器來簡化UI編程,特別是在異步場景下。

      3.?????????Power Threading Library - Jeffrey Richter的Power Threading Library實現了AsyncEnumerator,使用基于迭代器的coroutines提供簡化的異步編程模型。

      4.?????????Unity游戲引擎實現了coroutines。

      5.?????????Servelat Pieces - Yevhen Bobrov的Servelat Pieces項目為Silverlight WCF服務提供了透明的異步,并能夠異步調用任何同步方法。該項目的實現基于Caliburn的Coroutines迭代器和C#迭代器塊。

      6.?????????.NET 2.0+框架現在通過迭代器模式和yield關鍵字提供了半coroutine(生成器)功能。

      C# 5.0?提供?await?語法支持。

      7.4????Clojure中的實現

      Cloroutine是一個第三方庫,為Clojure中的無堆棧coroutine提供支持。它以宏的形式實現,在任意var調用時靜態地拆分任意代碼塊,并將coroutine作為有狀態函數發出。

      7.5????D中的實現

      D實現了coroutines作為它的標準庫類Fiber A生成器使得將光纖函數作為輸入范圍暴露出來變得微不足道,使得任何光纖與現有的范圍算法兼容。

      7.6????Java的實現

      Java中的coroutine有幾種實現方式。盡管有Java的抽象所帶來的限制,但JVM并不排除這種可能性,使用的一般方法有四種,但有兩種方法打破了符合標準的JVM之間的字節碼的可移植性。

      1.?????????修改后的JVM。可以構建一個打了補丁的JVM來更原生地支持coroutines。達芬奇JVM已經創建了補丁。

      2.?????????修改后的字節碼。Coroutine功能可以通過重寫常規的Java字節碼實現,無論是在飛行中還是在編譯時。工具包包括Javaflow、Java Coroutines和Coroutines。

      3.?????????特定平臺的JNI機制。這些使用在操作系統或C庫中實現的JNI方法來向JVM提供功能。

      4.?????????線程抽象。使用線程實現的Coroutine庫可能是重量級的,不過性能會根據JVM的線程實現而變化。

      7.7????Kotlin的實現

      Kotlin實現了coroutines作為第一方庫的一部分。

      7.8????在JavaScript中的實現

      1.?????????node-fibers

      a)????????Fibjs - fibjs是一個建立在Chrome的V8 JavaScript引擎上的JavaScript運行時,fibjs使用fibers-switch、同步風格和非阻塞I/O模型來構建可擴展系統。

      2.?????????自ECMAScript 2015年起,通過?"生成器"和yield表達式提供了無堆棧的coroutine功能。

      7.9????在Mono中實現

      Mono通用語言運行時支持連續性,可以從中構建coroutine。

      7.10??????在.NET框架中以fibers形式實現

      在.NET Framework 2.0的開發過程中,微軟擴展了通用語言運行時(CLR)托管API的設計,以處理基于光纖的調度,并著眼于將其用于SQL服務器的光纖模式。在發布之前,由于時間限制,取消了對任務切換鉤子ICLRTask::SwitchOut的支持。因此,在.NET框架中,使用光纖API來切換任務目前不是一個可行的選擇。

      Coroutine技術學習研究

      7.11??????PHP中的實現

      1.?????????Amphp

      7.12??????Python中的實現

      1.?????????Python 2.5?基于擴展的生成器,實現了對類似于coroutine的功能更好的支持?(PEP 342)

      2.?????????Python 3.3?改進了這一能力,支持委托給子生成器?(PEP 380)

      3.?????????Python 3.4引入了PEP 3156中標準化的全面異步I/O框架,其中包括利用子生成器授權的coroutines。

      4.?????????Python 3.5?引入了對使用?async/await?語法的?coroutine?的顯式支持?(PEP 0492)。

      5.?????????自?Python 3.7?起,async/await?成為保留關鍵字。

      6.?????????Eventlet

      7.?????????Greenlet

      8.?????????gevent

      9.?????????stackless python

      7.13??????Ruby中的實現

      1.?????????Ruby 1.9支持原生的coroutines,這些coroutines被實現為fiber,即半coroutines。

      2.?????????Marc De Scheemaecker的實現

      3.?????????Ruby 2.5和更高版本的Ruby支持原生的coroutines,這些coroutines以fiber的形式實現。

      4.?????????Thomas W Branson的實現

      7.14??????Perl中的實現

      1.?????????Coro

      Coroutines在所有的Raku后端都是原生實現的。

      7.15??????Rust中的實現

      Rust有一個提供coroutines的庫,生成器是一個實驗性的功能,可以在夜間的rust中使用,它提供了一個帶有async/await的coroutines的實現。

      7.16??????Scala中的實現

      Scala Coroutines[48]?是Scala的一個coroutine實現。這個實現是一個庫級擴展,它依靠Scala宏系統將程序的部分靜態地轉換為coroutine對象。因此,這個實現不需要在JVM中進行修改,所以它在不同的JVM之間是完全可移植的,并且可以與其他的Scala后端一起工作,比如編譯成JavaScript的Scala.js。

      Scala Coroutine依賴于coroutine宏,它將一個普通的代碼塊轉化為coroutine定義。這樣的coroutine定義可以通過調用操作來調用,從而實例化一個coroutine框架。可以用resume方法恢復coroutine框架,恢復coroutine主體的執行,直到達到yieldval關鍵字,暫停coroutine框架。Scala coroutine還公開了一個快照方法,它可以有效地復制coroutine.[50]在ECOOP 2018上出現了帶快照的Scala coroutine的詳細描述,以及它們的形式模型。

      7.17??????Swift中的實現

      SwiftCoroutine -?適用于iOS、macOS和Linux的Swift coroutine庫。

      Smalltalk的實現

      因為在大多數Smalltalk環境中,執行堆棧是一流的公民,所以無需額外的庫或虛擬機支持就可以實現coroutine。

      7.18??????Scheme中的實現

      由于Scheme提供了對連續性的完全支持,實現coroutine幾乎是微不足道的,只需要維護一個連續性的隊列。

      7.19??????工具命令語言(Tcl)中的實現

      從8.6版本開始,工具命令語言支持核心語言中的coroutine。

      7.20??????Vala中的實現

      Vala實現了對coroutine的本地支持。它們被設計為與Gtk主循環一起使用,但如果注意確保在做至少一個yield之前不需要調用結束回調,也可以單獨使用。

      7.21??????匯編語言中的實現

      依賴于機器的匯編語言往往提供了直接執行coroutine的方法。例如,在PDP-11系列微型計算機的匯編語言MACRO-11中,"經典的?"coroutine切換是由?"JSR PC,@(SP)+"指令實現的,它跳轉到從堆棧中彈出的地址,并將當前(即下一個)指令地址推到堆棧中。在VAXen上(在Macro-32中),類似的指令是?"JSB @(SP)+"。甚至在Motorola 6809上也有?"JSR [,S++]"指令;注意?"++",因為從堆棧中彈出了2個字節(地址)。這條指令在(標準) "顯示器?"輔助09中用得很多。

      8??????參考

      https://en.wikipedia.org/wiki/Async/await

      https://en.wikipedia.org/wiki/Generator_(computer_programming)

      https://en.wikipedia.org/wiki/Coroutine

      https://en.wikipedia.org/wiki/Protothreads

      軟件開發

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:uploadify在火狐下上傳不了的解決方案,java版(Spring+SpringMVC+MyBatis)詳細解決方案...
      下一篇:【Python算法】協同過濾算法——基于物品的協同過濾算法
      相關文章
      亚洲国产精品一区| 亚洲日韩av无码中文| 亚洲Av无码乱码在线znlu| 亚洲人成电影网站免费| 亚洲色大网站WWW永久网站| 亚洲资源最新版在线观看| 亚洲av无码片在线观看| 亚洲一级毛片免费观看| 亚洲第一成年网站大全亚洲| 亚洲欧洲日本精品| 久久精品国产亚洲av麻豆蜜芽 | 亚洲熟妇无码爱v在线观看| 亚洲美女人黄网成人女| 亚洲精品成人网站在线播放| 亚洲第一二三四区| 亚洲一区无码中文字幕乱码| 国产成人精品日本亚洲专区6| 四虎必出精品亚洲高清| 亚洲精品色播一区二区| 成人亚洲综合天堂| 国产精品亚洲二区在线观看| 国产亚洲精品久久久久秋霞| 亚洲国产精品无码中文字| 亚洲成色999久久网站| 亚洲综合激情九月婷婷| 亚洲国产成人99精品激情在线| 中文字幕亚洲码在线| 国产成人亚洲午夜电影| 国产精品亚洲综合专区片高清久久久| 国产亚洲情侣一区二区无码AV| 亚洲不卡av不卡一区二区| 97亚洲熟妇自偷自拍另类图片| 亚洲国产成人手机在线电影bd | 亚洲欧洲日产国码一级毛片| 久久久久久久亚洲精品| 亚洲Av永久无码精品三区在线| 亚洲网站在线观看| 亚洲制服丝袜第一页| 日本中文一区二区三区亚洲 | 亚洲一级在线观看| mm1313亚洲国产精品无码试看|