kotlin的suspend對比csharp的asyncawait

b1e066ac02c03498df2b8e5e167c9c0e.png

協程的出現大大降低了異步編程的復雜度,可以讓我們像寫同步代碼一樣去寫異步代碼,如果沒有它,那么很多異步的代碼都是需要靠回調函數來一層層嵌套,這個在我之前的一篇有介紹 rxjava回調地獄-kotlin協程來幫忙

本篇文章主要介紹

  • kotlin的suspend函數在編譯生成了怎樣的代碼

  • csharp的async&await在編譯生成了怎么樣的代碼

  • 這兩者相比較,引發怎樣的思考

kotlin的suspend函數demo

8b759c8eb64451b204ef8d4c5e89a813.png
image

這里針對kotlin的語法以及協程的具體用法細節不過多介紹,就當你已了解

稍微注意下runBlocking函數比較特別,

如下圖:它接受了一個suspend的block函數

3d8e2bb9ff6a69ff92c228cd80f4a541.png
image

所以我上面的demo這里面有其實有三個suspend函數!

在idea我們可以把這個kotlin代碼反編譯成java代碼

f56a1881744b2b837b6eb822dcb44543.png
image

這個反編譯后的java代碼 有很多報錯是無法直接copy出來運行的(這就沒有csharp做的好,csharp反編譯出來的代碼至少不會報紅),

5e98ee047324807fe1f9d7c0e2880225.png
image

看代碼的確是一個狀態機控制函數和一個匿名類,還原成正常可直接運行的java代碼如下:

測試用的coroutine版本為:
kotlinx-coroutines-jdk8:1.6.4
953d0179933f174769fa94be5e2911db.png
image

比如test1函數

public?static?Object?test1(Continuation?continuation)?{CoroutineTest1?continuationTest1;label20:{if?(continuation?instanceof?CoroutineTest1)?{continuationTest1?=?(CoroutineTest1)?continuation;int?i?=?continuationTest1.label?&?Integer.MIN_VALUE;if?(i?!=?0)?{continuationTest1.label?-=?Integer.MIN_VALUE;}break?label20;}continuationTest1?=?new?CoroutineTest1(continuation);}Object?result?=?(continuationTest1).result;Object?var4?=?IntrinsicsKt.getCOROUTINE_SUSPENDED();String?var1;switch?((continuationTest1).label)?{case?0:ResultKt.throwOnFailure(result);var1?=?"test1-start";System.out.println(var1);(continuationTest1).label?=?1;if?(test2(continuationTest1)?==?var4)?{return?var4;}break;case?1:ResultKt.throwOnFailure(result);break;default:throw?new?IllegalStateException("call?to?'resume'?before?'invoke'?with?coroutine");}var1?=?"test1-end";System.out.println(var1);return?Unit.INSTANCE;
}final?static?class?CoroutineTest1?extends?ContinuationImpl?{Object?result;int?label;public?CoroutineTest1(@Nullable?Continuation<Object>?completion)?{super(completion);}@Nullablepublic?Object?invokeSuspend(@NotNull?Object?$result)?{this.result?=?$result;this.label?|=?Integer.MIN_VALUE;return?test1(this);}
}

其他的函數也類似,完整的代碼請查看:

https://gist.github.com/yuzd/cf67048777f0eb8fc1b3757f5bf9e8f3

整個運行流程如下:a3cac0799a02a676b48ffaab330aaf88.png

kotlin協程的掛起點是怎么控制的,異步操作執行完后它知道從哪里恢復?

不難看出來suspend函數其實在編譯后是變成了狀態機,將我們順序執行的代碼,轉換成了回調的形式父suspend函數里面調用子suspend函數,其實是把自己傳給了子suspend狀態機,如果子函數掛起了,等子函數恢復后直接調用父函數(因為通過狀態機的label來控制走不同邏輯,去恢復當時的調用堆棧)

這就是協程的掛起與恢復機制了

csharp的async&await

demo

static?async?Task?Main(string[]?args)
{await?test1();??????Console.WriteLine("Let's?Go!");
}async?Task?test1(){Console.WriteLine("test1-start");await?test2();Console.WriteLine("test1-end");}async?Task?test2()
{Console.WriteLine("test2-start");await?Task.Delay(1000);Console.WriteLine("test2-end");}

我們反編譯查看下編譯器生成了怎樣的狀態機

8a3381414d7e5fc2c02039270beefe28.png
image

看反編譯的代碼比較吃力,我還原成了正常代碼,

static?Task?CreateMainAsyncStateMachine()
{MainAsyncStateMachine?stateMachine?=?new?MainAsyncStateMachine{_builder?=?AsyncTaskMethodBuilder.Create(),_state?=?-1};stateMachine._builder.Start(ref?stateMachine);return?stateMachine._builder.Task;
}struct?MainAsyncStateMachine?:?IAsyncStateMachine
{public?int?_state;public?AsyncTaskMethodBuilder?_builder;public?TaskAwaiter?_waiter;public?void?MoveNext(){int?num1?=?this._state;try{TaskAwaiter?awaiter;int?num2;if?(num1?!=?0){awaiter?=?UserQuery.CreateTest1AsyncStateMachine().GetAwaiter();if?(!awaiter.IsCompleted){Console.WriteLine("MainAsyncStateMachine######Test1AsyncStateMachine?IsCompleted:false,?注冊自己到Test1Async運行結束時運行");this._state?=?num2?=?0;this._waiter?=?awaiter;this._builder.AwaitUnsafeOnCompleted(ref?awaiter,?ref?this);return;}}else{Console.WriteLine("MainAsyncStateMachine######Test1AsyncStateMachine?IsCompleted:true");awaiter?=?this._waiter;this._waiter?=?new?TaskAwaiter();this._state?=?num2?=?-1;}awaiter.GetResult();Console.WriteLine("MainAsyncStateMachine######Let's?Go!");}catch?(Exception?e){this._state?=?-2;this._builder.SetException(e);return;}this._state?=?-2;this._builder.SetResult();}public?void?SetStateMachine(IAsyncStateMachine?stateMachine){this._builder.SetStateMachine(stateMachine);}
}

完整代碼請查看https://github.com/yuzd/asyncawait_study

可以看出來,和kotlin其實原理差不多,都是生成一個函數加一個狀態機

區別是csharp的函數就是創建一個狀態機且啟動它

//?當狀態機啟動時會觸發?狀態機的MoveNext方法的調用
stateMachine._builder.Start(ref?stateMachine);
b20a9d9d4394b2f503e4a34028762a43.png
image

整體的執行流程如下

bb983a3280ecf366f96a9a804d81dd89.png
image

ps:最右邊的是展示如果有多個await 那么就會對應這個狀態機的多個狀態

這兩者相比較,引發怎樣的思考

通過查看kotlin和csharp的實現方式,我發現kotlin的生成的狀態機(ContinuationImpl的實現)都是有繼承關系的, 比如demo中的test2繼承了test1,test繼承了main(通過構造函數傳遞的)

然而csharp中沒有這樣的關系

這也帶來了兩者最大的區別,kotlin的協程綁定了scope的概念,一旦scope被取消,那么scope綁定的所有的協程也都被取消。

這點好像在csharp中沒有(如果理解有誤歡迎指正)

這在實際應用中是怎么個區別呢,舉個例子

async?void?testAsyncA(){testAsyncB();//?我想取消,或者下面運行出異常了?我也無法取消testAsyncB這個任務}async?void?testAsyncB(){//?do?long?task
}

在kotlin是可以的

2bb3527117ffc795a7fa288779204393.png
image
suspend?fun?test2()?=?coroutineScope?{println("test2-start")async?{delay(100000);}delay(1000)println("test2-end")//?或者手動取消當前coroutineScopethis.cancel()
}

?我是正東,關注高效率編程~

24d140cc5e2a194e796f0d93f7a00755.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/280981.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/280981.shtml
英文地址,請注明出處:http://en.pswp.cn/news/280981.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

file協議 控制面板_如何在Windows File Explorer導航窗格中顯示控制面板和回收站

file協議 控制面板By default, the Windows File Explorer’s sidebar is divided into big categories like Quick Access, This PC, Network, and so on. But a quick setting change can make your navigation pane look a bit more like the traditional tree you’d see i…

hdu-2612-Find a way(廣搜,bfs)

Pass a year learning in Hangzhou, yifenfei arrival hometown Ningbo at finally. Leave Ningbo one year, yifenfei have many people to meet. Especially a good friend Merceki. Yifenfei’s home is at the countryside, but Merceki’s home is in the center of city.…

過濾器(Filter)

1 什么是過濾器 過濾器JavaWeb三大組件之一&#xff0c;它與Servlet很相似&#xff01;不它過濾器是用來攔截請求的&#xff0c;而不是處理請求的。 當用戶請求某個Servlet時&#xff0c;會先執行部署在這個請求上的Filter&#xff0c;如果Filter“放行”&#xff0c;那么會繼…

03-1.JavaScript基礎語法略寫/模版字符串

基礎語法 參考前端基礎之JavaScript - Q1mi - 博客園 略寫原因 由于后續主要用jQuery編寫&#xff0c;jQuery簡化編程。大概了解JavaScript語法即可。 jQuery是一個輕量級的、兼容多瀏覽器的JavaScript庫。jQuery使用戶能夠更方便地處理HTML Document、Events、實現動畫效果…

發布適用于 .NET 7 的 .NET MAUI

點擊上方藍字關注我們&#xff08;本文閱讀時間&#xff1a;6分鐘)我們在六個月前向您介紹了 .NET 多平臺應用程序 UI (MAUI)&#xff0c;現在我們很高興地宣布 .NET MAUI 在我們的下一個主要版本 .NET 7 中普遍可用。在此短的時間范圍內&#xff0c;我們在 .NET MAUI 中的主要…

bzoj3160(FFT+回文自動機)

題目描述 https://www.lydsy.com/JudgeOnline/problem.php?id3160 題解 先把問題轉化一下&#xff0c;我們要求的是非連續對稱回文子序列。 ans回文子序列數-回文子串數。 回文子串數可以用PAM或manachar求出來。 復習了一下PAM&#xff0c;用它求回文子串數和SAM一樣&#xf…

03:數據結構 棧、隊列、鏈表與數組

算法其他篇 目錄&#xff1a; 1.1 數據結構中的一些概念1.2 棧&#xff08;stack&#xff09;1.3 隊列1.4 鏈表1.5 python中字典對象實現原理1.6 數組1.1 數據結構中的一些概念 返回頂部 1、數據結構是什么 1、簡單來說&#xff0c;數據結果就是設計數據以何種方式存儲在計…

力登:以智能化管理提升數據中心服務能力成熟度

2017年2月28日&#xff0c;由全國信息技術標準化技術委員會信息技術服務分技術委員會指導的《信息技術服務數據中心服務能力成熟度模型》發布&#xff0c;在業界首次提出“數據中心服務能力成熟度”概念&#xff0c;使得數據中心的管理真正實現了數字化和持續優化&#xff0c;是…

基于.NET 7 的 WebTransport 實現雙向通信

Web Transport 簡介WebTransport 是一個新的 Web API&#xff0c;使用 HTTP/3 協議來支持雙向傳輸。它用于 Web 客戶端和 HTTP/3 服務器之間的雙向通信。它支持通過 不可靠的 Datagrams API 發送數據&#xff0c;也支持可靠的 Stream API 發送數據。因為 HTTP/3 使用了基于 UDP…

Django01: 安裝/基礎命令/設置筆記

安裝 按官網版本支持&#xff0c;現在比較適合使用1.11版本。 下載安裝命令 pip3 install django1.11.9 新建項目 django-admin startproject mysite 運行項目 python manage.py runserver 127.0.0.1:8000 運行相關 目錄介紹 mysite/ ├── manage.py # 管理文件 └…

JavaScript校驗網址

gistfile1.txt var linkUrl https://www.baidu.com if( typeof (linkUrl) ! undefined &amp;&amp; linkUrl ! ){var strRegex ^((https|http|ftp|rtsp|mms)?://) ?(([0-9a-z_!~*\().&amp;$%-]: )?[0-9a-z_!~*\().&amp;$%-])? //ftp的user (([0-9]{1,3}.)…

線上問題隨筆記錄數據庫連接池問題

修改方法 轉載于:https://www.cnblogs.com/lvgg/p/8581506.html

數據底座_體驗當今計算機的未來:通過智能底座將您的Galaxy S4變成PC

數據底座Have you ever thought that Smartphones these days are so advanced they could actually replace the PC in your everyday computing life? Today, we here at HTG will review using the Galaxy S4 with the “Smart Dock Multimedia Hub” as a PC replacement.…

如何實現 WPF 代碼查看器控件

如何實現 WPF 代碼查看器控件CodeViewer作者&#xff1a;WPFDevelopersOrg - 驚鏵原文鏈接[1]&#xff1a;https://github.com/WPFDevelopersOrg/WPFDevelopers框架使用.NET40&#xff1b;Visual Studio 2019;代碼展示需要使用到AvalonEdit是基于WPF的代碼顯示控件&#xff0c;…

談大數據也談人工智能 郭為告訴你一個不一樣的神州控股

毋庸置疑&#xff0c;我們深處一個數據無處不在的時代&#xff0c;也就是大數據時代。作為中國智慧城市領導者的神州數碼控股有限公司&#xff08;以下簡稱“神州控股”&#xff09;近年來也在積極布局大數據&#xff0c;不過在神州控股董事局主席郭為看來&#xff0c;神州控股…

Django02: pycharm上配置django

1.setting導入 File-->Setting-->Project-->Project Interface 2.new project 新窗口 圖片畫錯 3.調試 點擊右上角調試

vue-cli中配置sass

https://www.cnblogs.com/rainheader/p/6505366.html轉載于:https://www.cnblogs.com/aidixie/p/10213997.html

php 常用函數

用到就記下來&#xff0c;持續更新......... __call(string $func_name, array args){}public方法不存在 調用此函數 通過pg_系列函數與Postgres 數據庫交互 note: php 取得對象的某一共有屬性&#xff0c;若不存在則 查看是否有get方法(魔術方法) 若有則取get方法的返回值&am…

dropbox_來自提示框:望遠鏡激光瞄準器,Dropbox桌面和Kindle剪輯轉換

dropboxOnce a week we round up some great reader tips and share them with everyone; this week we’re looking at telescope laser sights, syncing your desktop with Dropbox, and converting your Kindle Clippings file. 每周一次&#xff0c;我們收集一些很棒的讀者…

在 EF Core 7 中實現強類型 ID

本文主要介紹 DDD 中的強類型 ID 的概念&#xff0c;及其在 EF 7 中的實現&#xff0c;以及使用 LessCode.EFCore.StronglyTypedId 這種更簡易的上手方式。背景在楊中科老師 B 站的.Net Core 視頻教程[1]其中 DDD 部分講到了強類型 ID&#xff08;Strongly-typed-id&#xff09…