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.mzph.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…

过滤器(Filter)

1 什么是过滤器 过滤器JavaWeb三大组件之一&#xff0c;它与Servlet很相似&#xff01;不它过滤器是用来拦截请求的&#xff0c;而不是处理请求的。 当用户请求某个Servlet时&#xff0c;会先执行部署在这个请求上的Filter&#xff0c;如果Filter“放行”&#xff0c;那么会继…

发布适用于 .NET 7 的 .NET MAUI

点击上方蓝字关注我们&#xff08;本文阅读时间&#xff1a;6分钟)我们在六个月前向您介绍了 .NET 多平台应用程序 UI (MAUI)&#xff0c;现在我们很高兴地宣布 .NET MAUI 在我们的下一个主要版本 .NET 7 中普遍可用。在此短的时间范围内&#xff0c;我们在 .NET MAUI 中的主要…

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 # 管理文件 └…

线上问题随笔记录数据库连接池问题

修改方法 转载于: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.调试 点击右上角调试

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…

如何快速打造一款高清又极速的短视频APP?

2019独角兽企业重金招聘Python工程师标准>>> 整个短视频的市场规模一直在增长&#xff0c;网络数据显示2018年已经突破100亿大关&#xff0c;在2019年预测将超过200亿。纵观行业&#xff0c;在生活资讯、美食、搞笑、游戏、美妆等领域&#xff0c;短视频流量巨大但竞…

Django03: django加入APP

使用命令在已有project创建 1.创建 在manage.py同级运行命令 python manage.py startapp app01 2.django中加入app 在settings.py里的INSTALLED_APPS加入app01.apps.App01Config, INSTALLED_APPS [django.contrib.admin,django.contrib.auth,django.contrib.contenttype…

如何将Windows 10帐户还原为本地帐户(在Windows Store劫持它之后)

If your Windows 10 user account is currently a Microsoft account (by your choice or because you got, one way or another, roped into it) it’s easy to revert it back to a local account if you know where to look. Read on as we show you how. 如果您的Windows 1…

【译】Dapr 是一个“10倍好”平台 !?

译者注在正式阅读本文之前&#xff0c;我们有必要先了解下什么是“10 倍好”。10 倍好理论最早出自彼得蒂尔的《从 0 到 1》&#xff0c;他说一个新创企业&#xff0c;要想获得快速成长&#xff0c;其提供的解决方案要比现有方案好 10 倍以上&#xff0c;这个好 10 倍&#xff…

1. ReactJS基础(开发环境搭建)

本文主要介绍通过React官方提供的create-react-app脚手架进行开发环境的搭建。 1.安装node环境(安装过程这里不做介绍&#xff0c;可参考其他博文) 在cmd中输入node -v 如果可以看到相应版本号&#xff0c;说明node环境安装成功 2.npm全局安装create-react-app脚手架 3.cmd命令…

“云计算+DevOps”的正确打开方式

以我们的经验看&#xff0c;技术和工具是很重要&#xff0c;但是技术和工具本身却不能产生价值&#xff0c;而将DevOps和云计算结合却可以。事实上&#xff0c;云计算的特性决定了&#xff0c;云计算和DevOps势必如影随形&#xff0c;而云计算与DevOps的结合也正在为企业用户提…