美文网首页
C#中的异步任务类型记录

C#中的异步任务类型记录

作者: 卅云川 | 来源:发表于2021-09-17 17:26 被阅读0次

    C#从7.2开始引入了“类任务”(task-like)概念,使asyncawait的使用不再限制于voidTaskTask<T>类型,我们可以实现自己需要的类型使用异步。不过之前一直没了解过其内部流程,最近借工作需要对这一部分内容进行了学习,并做整理记录。如有问题,望指正。

    核心记录的问题:

    1. AsyncMethodBuilderAttribute究竟是什么?
    2. 声明AsyncMethodBuilderAttribute时所用的类型有什么用?

    首先,一切的发端都是先从roslyn的C#中的异步任务类型看起。

    在这篇文章里,将AsyncMethodBuilderAttribute的作用、自定义Task与Awaiter的声明规范、自定义的TaskMethodBuilder及运行机制都进行了明确的阐述。下面将根据这份阐述,结合实际运行的例子进行整理。

    自定义TaskMethodBuilder的用途

    网上学习时看到一句话:自定义一个TaskMethodBuilder的目的,是为了供编译器将它的异步机制"绑定"到我们的自定义类型。这么说很晦涩也很抽象,所以我们用具体的例子进行说明。

    async void Func(){
      await Something();
    }
    
    MyTask Something(){
      return new MyTask();
    }
    

    上面这段代码中,MyTask就是我们的自定义任务类型。如果这样去使用,那么也就和TaskMethodBuilder没什么关系了,而其运行结果的本质与await new MyTask()相同,会依次调用MyTaskGetAwaiter(),以及对应AwaiterIsCompletedGetResult()

    再看另一个例子。

    async void Func(){
      await Something();
    }
    
    async MyTask Something(){
      await new MyTask();
    }
    

    上面的这段代码,当运行到await Something()时,会依次调用TaskMethodBuilderCreate()Start()SetResult()方法。而在Start()中,我们调用了状态机的MoveNext()(这也是构建TaskMethodBuilder类需要遵循的规范之一),在这里会就会执行Something()中的代码。

    所以那段很抽象的话,其实也可以表述为:使用async修饰的自定义任务类型,编译器通过我们自定义的TaskMethodBuilder实现。

    AsyncMethodBuilderAttribute的作用

    AsyncMethodBuilderAttribute作为一个属性,它用于形容一个任务类型(这个任务类型可以是类,也可以是结构体),目的是为了将这个任务类型与一个TaskMethodBuilder进行关联。如果没有这个属性,可以自己定义,将其放在System.Runtime.CompilerServices命名空间下即可。

    INotifyCompletion与ICriticalNotifyCompletion

    INotifyCompletionICriticalNotifyCompletion这两个接口都定义了OnCompleted(action)方法,用于任务结束时调用。二者区别在于:INotifyCompletion用于任务同步完成后被调用,ICriticalNotifyCompletion用于等待任务完成后被调用。

    简单理解,这两个接口一个定义了任务立即完成时的行为,一个定义等待后完成时的行为。不过在Builder的处理中,也体现了二者某种程度上区别不大的特点。

    相关文章

      网友评论

          本文标题:C#中的异步任务类型记录

          本文链接:https://www.haomeiwen.com/subject/hnhsgltx.html