协程的出现大大降低了异步编程的复杂度,可以让我们像写同步代码一样去写异步代码,如果没有它,那么很多异步的代码都是需要靠回调函数来一层层嵌套,这个在我之前的一篇有介绍 rxjava回调地狱-kotlin协程来帮忙
本篇文章主要介绍
这里针对kotlin的语法以及协程的具体用法细节不过多介绍,就当你已了解
稍微注意下runBlocking函数比较特别,
如下图:它接受了一个suspend的block函数
所以我上面的demo这里面有其实有三个suspend函数!
在idea我们可以把这个kotlin代码反编译成java代码
这个反编译后的java代码 有很多报错是无法直接copy出来运行的(这就没有csharp做的好,csharp反编译出来的代码至少不会报红),
看代码的确是一个状态机控制函数和一个匿名类,还原成正常的java代码如下:
比如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); } @Nullable public Object invokeSuspend(@NotNull Object $result) { this.result = $result; this.label |= Integer.MIN_VALUE; return test1(this); }}
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:
default:
throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
var1 = "test1-end";
return Unit.INSTANCE;
final static class CoroutineTest1 extends ContinuationImpl {
Object result;
int label;
public CoroutineTest1(@Nullable Continuation<Object> completion) {
super(completion);
@Nullable
public Object invokeSuspend(@NotNull Object $result) {
this.result = $result;
this.label |= Integer.MIN_VALUE;
return test1(this);
其他的函数也类似,完整的代码请查看:
https://gist.github.com/yuzd/cf67048777f0eb8fc1b3757f5bf9e8f3
整个运行流程如下:
不难看出来suspend函数其实在编译后是变成了状态机,将我们顺序执行的代码,转换成了回调的形式 父suspend函数里面调用子suspend函数,其实是把自己传给了子suspend状态机,如果子函数挂起了,等子函数恢复后直接调用父函数(因为通过状态机的label来控制走不同逻辑,去恢复当时的调用堆栈)
这就是协程的挂起与恢复机制了
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"); }
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");
我们反编译查看下编译器生成了怎样的状态机
看反编译的代码比较吃力,我还原成了正常代码,
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); }}
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);
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);
// 当状态机启动时会触发 状态机的MoveNext方法的调用
整体的执行流程如下
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}
async void testAsyncA(){
testAsyncB();
// 我想取消,或者下面运行出异常了 我也无法取消testAsyncB这个任务
async void testAsyncB(){
// do long task
在kotlin是可以的
suspend fun test2() = coroutineScope { println("test2-start") async { delay(100000); } delay(1000) println("test2-end") // 或者手动取消当前coroutineScope this.cancel()}
suspend fun test2() = coroutineScope {
println("test2-start")
async {
delay(100000);
delay(1000)
println("test2-end")
// 或者手动取消当前coroutineScope
this.cancel()
原文链接:https://www.cnblogs.com/yudongdong/p/16910049.html
本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728