【C# TAP 异步编程】二 、await运算符已经可等待类型Awaitable

await的作用:

1、await是一个标记,告诉编译器生成一个等待器来等待可等待类型实例的运行结果。

2、一个await对应一个等待器 ,任务的等待器类型是TaskAwaiter/TaskAwaiter<TResult>。

3、Await 就像一个一元运算符:它接受一个参数,一个可等待的"awaitable"类型的实例。它暂停对其所属的 async 方法的求值,直到其 【操作数】 表示的异步操作完成。 异步操作完成后,await 运算符将返回操作的结果(如果有)。

await task等效于task.GetAwaiter().GetResult()。task.GetAwaiter() 返回TaskAwaiter/TaskAwaiter<TResult>

4、可等待类型awaitable:TaskTask<TResult>、ValueTask、Task.Yield()、ConfiguredTaskAwaitable ConfigureAwait()、包含GetAwaiter()的鸭子类型

 

等待者模式

Await/Async 异步使模式使用的是等待者模式。等待者模式要求等待者公开IsCompleted属性,GetResult方法和OnCompleted方法(可选地带有UnsafeOnCompleted方法,unsafe表示不使用可执行上下 回导致漏洞)。

await用法

await 类型实例TTT

该【类型实例TTT】的类型必须包含 GetAwaiter()方法,并且GetAwaiter()方法的返回值类型继承INotifyCompletion接口,实现属性public bool IsCompleted { get; },方法public void GetResult() { }。使用方法和枚举器IEnumerable、 Enumerator一样。

例如:Task类包含GetAwaiter()方法,GetAwaiter()方法的返回值TaskAwaiter类 继承INotifyCompletion接口,TaskAwaiter类实现属性IsCompleted和方法GetResult()。
 

//Task类型
  public TaskAwaiter GetAwaiter()
        {
            return new TaskAwaiter(this);
        }
 ///TaskAwaiter类 实现了属性IsCompleted、方法GetResult()以及INotifyCompletion接口

明白原理后,自定义一个类

using System.Runtime.CompilerServices;

Task t = AsynchronousProcessing();
t.Wait();
Console.ReadLine();
static async Task AsynchronousProcessing()
{
    var sync = new CustomAwaitable(true);
    string result = await sync;
    // Completed synchronously
    Console.WriteLine(result);

    var async = new CustomAwaitable(false);
    result = await async;
    // Task is running on a thread id 3. Is thread pool thread: True
    Console.WriteLine(result);
}

/// <summary>
/// 类型t
/// </summary>
class CustomAwaitable
{
    private readonly bool _completeSynchronously;

    public CustomAwaitable(bool completeSynchronously)
    {
        _completeSynchronously = completeSynchronously;
    }

    /// <summary>
    /// t有一个名为GetAwaiter的可访问的实例或扩展方法
    /// </summary>
    /// <returns>类型A</returns>
    public CustomAwaiter GetAwaiter()
    {
        return new CustomAwaiter(_completeSynchronously);
    }
}

/// <summary>
/// 类型A 实现了 System.Runtime.CompilerServices.INotifyCompletion 接口
/// </summary>
class CustomAwaiter : INotifyCompletion
{
    private string _result = "Completed synchronously";
    private readonly bool _completeSynchronously;

    /// <summary>
    /// A有一个可访问的、可读的类型为bool的实例属性IsCompleted
    /// 如果IsCompleted属性返回true,则只需同步调用GetResult方法
    /// </summary>
    public bool IsCompleted => _completeSynchronously;

    public CustomAwaiter(bool completeSynchronously)
    {
        _completeSynchronously = completeSynchronously;
    }

    /// <summary>
    /// A有一个名为GetResult的可访问的实例方法,该方法没有任何参数和类型参数。
    /// </summary>
    /// <returns></returns>
    public string GetResult()
    {
        return _result;
    }

    public void OnCompleted(Action continuation)
    {
        ThreadPool.QueueUserWorkItem(state =>
        {
            Thread.Sleep(TimeSpan.FromSeconds(1));
            _result = GetInfo();
            continuation?.Invoke();
        });
    }

    private string GetInfo()
    {
        return $"Task is running on a thread id {Thread.CurrentThread.ManagedThreadId}. " +
            $"Is thread pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
    }



}

 

 

 

 

await 的异步方法的刨析

通过一段代码来了解await,把这编译后,用ILspy 反编译。

namespace MyTask;
  class Program
    {
        public static  void Main(string[] args)
        {
            Task<string> baconTask =  FryBaconAsync(3);
        baconTask.ContinueWith(t =>Console.WriteLine(t.Result));
            Console.Read();
        }
        static async Task<string> FryBaconAsync(int slices)
        {
        HttpClient httpClient=new HttpClient();

        string content = await httpClient.GetStringAsync("https://www.cnblogs.com/cdaniu/p/15681416.html");
        return content; //整数3和Task<int>不存在隐形转化啊,怎么就可以return 3; 如果你也存在这个疑问 请继续往下阅读,接下去详细分析。
        }
}

用ILspy 反编译后的完整代码:

// MyTask.Program
using System;
using System.Diagnostics;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using MyTask;

[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
internal class Program
{
    [Serializable]
    [CompilerGenerated]
    private sealed class <>c
    {
        [System.Runtime.CompilerServices.Nullable(0)]
        public static readonly <>c <>9 = new <>c();

        [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1, 1 })]
        public static Action<Task<string>> <>9__0_0;

        internal void <Main>b__0_0(Task<string> t)
        {
            Console.WriteLine(t.Result);
        }
    }

    [CompilerGenerated]
    private sealed class <FryBaconAsync>d__1 : IAsyncStateMachine
    {
        public int <>1__state;

        [System.Runtime.CompilerServices.Nullable(0)]
        public AsyncTaskMethodBuilder<string> <>t__builder;

        public int slices;

        [System.Runtime.CompilerServices.Nullable(0)]
        private HttpClient <httpClient>5__1;

        [System.Runtime.CompilerServices.Nullable(0)]
        private string <content>5__2;

        [System.Runtime.CompilerServices.Nullable(0)]
        private string <>s__3;

        [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })]
        private TaskAwaiter<string> <>u__1;

        private void MoveNext()
        {
            int num = <>1__state;
            string result;
            try
            {
                TaskAwaiter<string> awaiter;
                if (num != 0)
                {
                    <httpClient>5__1 = new HttpClient();
                    awaiter = <httpClient>5__1.GetStringAsync("https://www.cnblogs.com/cdaniu/p/15681416.html").GetAwaiter();
                    if (!awaiter.IsCompleted)
                    {
                        num = (<>1__state = 0);
                        <>u__1 = awaiter;
                        <FryBaconAsync>d__1 stateMachine = this;
                        <>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
                        return;
                    }
                }
                else
                {
                    awaiter = <>u__1;
                    <>u__1 = default(TaskAwaiter<string>);
                    num = (<>1__state = -1);
                }
                <>s__3 = awaiter.GetResult();
                <content>5__2 = <>s__3;
                <>s__3 = null;
                result = <content>5__2;
            }
            catch (Exception exception)
            {
                <>1__state = -2;
                <httpClient>5__1 = null;
                <content>5__2 = null;
                <>t__builder.SetException(exception);
                return;
            }
            <>1__state = -2;
            <httpClient>5__1 = null;
            <content>5__2 = null;
            <>t__builder.SetResult(result);
        }

        void IAsyncStateMachine.MoveNext()
        {
            //ILSpy generated this explicit interface implementation from .override directive in MoveNext
            this.MoveNext();
        }

        [DebuggerHidden]
        private void SetStateMachine(IAsyncStateMachine stateMachine)
        {
        }

        void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
        {
            //ILSpy generated this explicit interface implementation from .override directive in SetStateMachine
            this.SetStateMachine(stateMachine);
        }
    }

    public static void Main(string[] args)
    {
        Task<string> baconTask = FryBaconAsync(3);
        baconTask.ContinueWith(<>c.<>9__0_0 ?? (<>c.<>9__0_0 = new Action<Task<string>>(<>c.<>9.<Main>b__0_0)));
        Console.Read();
    }

    [AsyncStateMachine(typeof(<FryBaconAsync>d__1))]
    [DebuggerStepThrough]
    private static Task<string> FryBaconAsync(int slices)
    {
        <FryBaconAsync>d__1 stateMachine = new <FryBaconAsync>d__1();
        stateMachine.<>t__builder = AsyncTaskMethodBuilder<string>.Create();
        stateMachine.slices = slices;
        stateMachine.<>1__state = -1;
        stateMachine.<>t__builder.Start(ref stateMachine);
        return stateMachine.<>t__builder.Task;
    }
}
View Code

 

编译器根据await生成一个等待器awaiter,用这个awaiter 等待异步方法运行的结果。然后程序通过return;把控制权还给了调用函数,

可等待的数据类型-Awaitable Type

编译器采用鸭子类型来判断可等待类型。即一个Type包含 public WorkItemAwaiter GetAwaiter()方法就是可等待类型。返回值WorkItemAwaiter的类型必须继承INotifyComplete接口和有 public void GetResult() 方法、 public bool IsCompleted{get;}属性。和枚举器(Enumerable、Enumerator)的原理一样

自定义一个可等待的数据类型 WorkItem

using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
Debug.WriteLine("sfsdfs");
Test();

async WorkItem Test()
{

   await new WorkItem();

}
public class WorkItem
{
    public WorkItemAwaiter GetAwaiter()
    {
        return new WorkItemAwaiter(this);
    }
    internal volatile int m_StateFlag;
 
    public bool IsCompleted
    {
        get
        {
            int stateFlag = m_StateFlag;
            return IsCompletedMethod(stateFlag);
        }
    }

    private bool IsCompletedMethod(int stateFlag)
    {
        //判断完成
        return (stateFlag & (int)TestStateFlag.Completed) != 0;
    }

    //  m_StateFlag的常量
    internal enum TestStateFlag
    {
        Start = 0x0001,                    // bin: 0000 0000 0000 0000 0000 0000 0000 0001
        Running = 0x0002,                  // bin: 0000 0000 0000 0000 0000 0000 0000 0010
        Waiting = 0x0004,                  // bin: 0000 0000 0000 0000 0000 0000 0000 0100
        Completed = 0x0008,                // bin: 0000 0000 0000 0000 0000 0000 0000 1000

        WaitCompleteNotifyed = 0x0010,    // bin: 0000 0000 0000 0000 0000 0000 0001 0000


    }
    // 
    internal bool IsWaitNotificationEnabledOrNotCompleted =>
          (m_StateFlag & ((int)TestStateFlag.WaitCompleteNotifyed | (int)TestStateFlag.Completed)) != (int)TestStateFlag.Completed;
}
/// <summary>
/// 
/// </summary>
public class WorkItemAwaiter : ICriticalNotifyCompletion
{
    internal readonly WorkItem m_WorkItem;
   
    public WorkItemAwaiter(WorkItem workItem)
    {
       this.m_WorkItem = workItem;
    }
    public bool IsCompleted=> m_WorkItem.IsCompleted;
   

    public void OnCompleted(Action continuation)
    {
        throw new NotImplementedException();
    }

    public void UnsafeOnCompleted(Action continuation)
    {
        throw new NotImplementedException();
    }

    public void GetResult()
    {
       ValidateEnd(m_WorkItem);
    }
    /// <summary>
    ///快速检查一个await操作是否结束,以确定在完成await操作之前是否需要做更多的操作。
    /// </summary>
    /// <param name="task">The awaited task.</param>
    internal static void ValidateEnd(WorkItem workItem)
    {
        // 快速检测
        if (workItem.IsWaitNotificationEnabledOrNotCompleted)
        {

        }

    }
    internal void SpinUntilCompleted()
    {
        // Spin wait until the completion is finalized by another thread.
        SpinWait sw = default;
        while (!IsCompleted)
        {
            sw.SpinOnce();
        }
    }

}
 

 

posted @ 2021-12-17 21:50  小林野夫  阅读(789)  评论(1)    收藏  举报
原文链接:https://www.cnblogs.com/cdaniu/