学习笔记,基于任务的异步模式

异步操作的生命周期

Task 类提供了异步操作的生命周期,且该周期由 TaskStatus 枚举表示。

状态 执行顺序 备注
Created 0 该任务已初始化,但尚未安排。
WaitingForActivation 1 该任务正在等待被.NET Framework infrastructure 内部激活和调度。
WaitingToRun 2 该任务已安排执行但尚未开始执行。
Running 3 任务正在运行但尚未完成。
WaitingForChildrenToComplete 4 任务已完成执行,并隐式等待附加的子任务完成。
RanToCompletion 5 任务已成功完成执行。
Canceled 6 引发 OperationCanceledException 异常,或者在任务开始执行之前取消
Faulted 7 由于未处理的异常,任务已完成。

Canceled 和
Faulted状态都会因为任务至极导致转变为这场所。二者的分别如下:

假使标识的 IsCancellationRequested 属性再次来到false,或然极度的暗号与职务的符号不相配,则会将
OperationCanceledException 依据一般的可怜来拍卖,进而致使任务转变为
Faulted 状态。 别的还要注意,别的极其的留存将也会招致义务转变为
Faulted 状态。 您能够在 Status 属性中赢得已做到任务的情事。

参照文章:

  • async(C#
    参考)
  • 运用 Async 和 Await 的异步编程(C#)
  • 听别人说职责的异步模式(TAP)
  • 异步重回类型
    (C#)
  • 异步程序中的调节流
    (C#)
  • 职分撤消
  • 异步编制程序

编辑异步方法


C# 中 asyncawait
关键字是异步编制程序的主干。通过那五个根本字就足以轻易创设异步方法,大致与创造同步方法同样。如下所示的
WPF 程序,布局文件上有个按键和文本框:

private async void StartButton_Click(object sender, RoutedEventArgs e)

{

    // Call and await separately.

    //Task<int> getLengthTask = AccessTheWebAsync();

    //// You can do independent work here.

    //int contentLength = await getLengthTask;

 

    int contentLength = await AccessTheWebAsync();

 

    resultsTextBox.Text +=

        String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);

}

 

 

// Three things to note in the signature:

//  - The method has an async modifier. 

//  - The return type is Task or Task<T>. (See "Return Types" section.)

//    Here, it is Task<int> because the return statement returns an integer.

//  - The method name ends in "Async."

async Task<int> AccessTheWebAsync()

{ 

    // You need to add a reference to System.Net.Http to declare client.

    HttpClient client = new HttpClient();

 

    // GetStringAsync returns a Task<string>. That means that when you await the

    // task you'll get a string (urlContents).

    Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

 

    // You can do work here that doesn't rely on the string from GetStringAsync.

    DoIndependentWork();

 

    // The await operator suspends AccessTheWebAsync.

    //  - AccessTheWebAsync can't continue until getStringTask is complete.

    //  - Meanwhile, control returns to the caller of AccessTheWebAsync.

    //  - Control resumes here when getStringTask is complete. 

    //  - The await operator then retrieves the string result from getStringTask.

    string urlContents = await getStringTask;

 

    // The return statement specifies an integer result.

    // Any methods that are awaiting AccessTheWebAsync retrieve the length value.

    return urlContents.Length;

}

 

 

void DoIndependentWork()

{

    resultsTextBox.Text += "Working . . . . . . .\r\n";

}

实行结果:

Working . . . . . . .

 

Length of the downloaded string: 41609.

说明:

1,当程序访谈互连网时,无论你什么样拖拽、最大化最小化、怎么样点击,UI
都不会失掉响应;

2,“async Task<int>
AccessTheWebAsync()”方法签字,有三点必要静心:1)有 async
修饰符;2)重返类型是 TaskTask<int>。该方法是
Task<int>,因为它回到的是链接内容的轻重;3)方法名以 Async
结尾;

3,“string urlContents = await
getStringTask;”语句,有四点必要潜心:1)AccessTheWebAsync 方法直到
getStringTask 完结手艺接二连三;2)同不常间,调节流重回到
AccessTheWebAsync 的调用者;3)getStringTask
完结后,调整流才会还原;4)之后,await 操作符从 getStringTask
检索结果。

下边总结让一个演示成为异步方法的风味:

  • 格局具名包括三个 async 修饰符。
  • 依据预定,异步方法的称号以“Async”后缀结尾。
  • 重临类型为下列项目之一:
    • 如果你的艺术有 TResult 类型的归来语句,则为
      Task<TResult>。
    • 假定你的法子未有回去语句,则为 Task。
    • 比方您编写的是异步事件管理程序,则为 Void(Visual Basic 中为
      Sub)。
  • 主意一般包括至少一个 await
    表明式,该表达式标识多个点,在该点上,直到等待的异步操作达成章程技术承袭。同期,将艺术挂起,並且控件再次回到到艺术的调用方。

在异步方法中,可使用提供的根本字和项目来提示要求产生的操作,且编写翻译器会成功别的操作,在这之中囊括不断追踪控件以挂起方法重返等待点时产生的状态。
一些不奇怪流程(比如,循环和特别管理)在观念异步代码中拍卖起来只怕很劳苦。
在异步方法中,成分的编辑撰写频率与共同技术方案一样且此难点得到化解。

在不帮忙的平台,安装NuGet包 Microsoft.Bcl.Async

正文内容

  • 概述
  • 编写异步方法
  • 异步程序中的调控流
  • API 异步方法
  • 线程
  • 异步和等候
  • 回去类型和参数
  • 参谋资料

各平台对async的支撑情状

回到类型和参数


.NET Framework 异步编制程序中异步方法一般再次回到 Task 或 Task<TResult>。
在异步方法中,await 运算符应用于通过调用另二个异步方法再次回到的职务。

一旦格局包括 Return (Visual Basic) 或内定项目 TResult 的操作数的 return
(C#) 语句,则将 Task<TResult> 钦命为回到类型。

借使艺术不含任何 return 语句或带有不回去操作数的 return 语句,则将 Task
用作重临类型。

上面包车型大巴亲自过问演示怎样注明并调用可回到 Task<TResult> 或 Task 的诀要。

// Signature specifies Task<;TResult>

async Task<;int> TaskOfTResult_MethodAsync()

{

    int hours;

    // . . .

    // Return statement specifies an integer result.

    return hours;

}

 

// Calls to TaskOfTResult_MethodAsync

Task<;int> returnedTaskTResult = TaskOfTResult_MethodAsync();

int intResult = await returnedTaskTResult;

// or, in a single statement

int intResult = await TaskOfTResult_MethodAsync();

// Signature specifies Task

async Task Task_MethodAsync()

{

    // . . .

    // The method has no return statement.  

}

 

// Calls to Task_MethodAsync

Task returnedTask = Task_MethodAsync();

await returnedTask;

// or, in a single statement

await Task_MethodAsync();

种种重临的任务表示正在开展的办事。
职分可包裹有关异步进度意况的音讯,假使未成功,则最后会卷入来自进度的终极结果或进度引发的那一个。

异步方法还足以是 Sub 方法 (Visual Basic) 或有所 void 重返类型 (C#)。
该再次来到类型重要用于定义必要 void 再次来到类型的事件管理程序。
异步事件管理程序日常作为异步程序的发轫点。

不能够等待为 Sub 程序或持有 void
再次回到类型的异步方法,并且无效的归来方法的调用方无法捕获该方法引发的其他特别。

异步方法不能注解 Visual Basic 中的 ByRef 参数或 C# 中的 ref 或 out
参数,但此方法能够调用具有此类参数的主意。

至于越多音信和演示,请参见异步重临类型(C# 和 Visual Basic)。
有关如何在异步方法中捕捉格外的越多音信,请参见 try-catch(C# 参考)或
Try…Catch…Finally 语句 (Visual Basic)。

Windows 运转时编制程序中的异步 API 具备下列重返类型之一,它就如于职分:

  • IAsyncOperation,它对应于 Task<TResult>
  • IAsyncAction,它对应于 Task
  • IAsyncActionWithProgress
  • IAsyncOperationWithProgress

异步方法的定义和注意事项

使用 async 关键字定义的异步方法简称为“异步方法”。

注意事项:

  • 如果 async 关键字修改的不二秘籍不包蕴 await
    表明式或讲话,则该办法将一块实践。 编写翻译器警告将公告你不包涵 await
    语句的其余异步方法,因为这一场馆或然意味着存在不当。
    请参阅编写翻译器警告(品级1)CS4014。
  • async 关键字是上下文关键字,原因在于只有当它修饰方法、lambda
    表明式或佚名格局时,它才是第一字。
    在具备其余上下文中,都会将其演说为标记符。
  • 不要用 void 作为 async 方法的归来类型! async 方法能够回到
    void ,可是那只限于编写事件管理程序。多个平凡的 async
    方法若无重返值,要重返Task ,而不是 void
  • 绝对要制止选取Task.WaitTask<T>.Result
    方法,因为它们会促成死锁。假使选取了 async ,最佳就一直采用它。
  • 异步方法的参数无法使用outrefoutref
    再次来到的多少应借用Task<TResult> 再次来到,能够行使元组或自定义数据结构。

下载 Demo TPL 与 APM 和 EAP 结合(APM 和 EAP 这三个标准异步方式已经不能够适应多核时期,但前边用这两种方法写的代码如何做?——把它们改变一下,跟 TPL 结合)

异步再次来到类型

上边提到 void 作为再次来到结果,适用于事件管理程序。
举例:

using System;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    public class TestVoidAsync
    {
        private event EventHandler<EventArgs> DoTest;

        public TestVoidAsync()
        {
            DoTest += DoTestEvent;
        }

        private static async void DoTestEvent(object sender, EventArgs e)
        {
            await Task.Delay(1000);
        }

        protected virtual void OnDoTest()
        {
            DoTest?.Invoke(this, EventArgs.Empty);
        }
    }
}

void 作为再次来到结果存在一个弊病:不能够捕获非凡。

回到 void
的异步方法的调用方不能够捕获从该办法引发的十一分,且此类未经管理的不胜也许会导致应用程序故障。
假使回到 TaskTask<TResult>
的异步方法中出现非常,此十三分将储存于重临的任务中,并在等待该职务时再度迷惑。

通用的异步重临类型:

从 C# 7.0 初阶,异步方法可回到任何拥有可访谈的 GetAwaiter
方法的花色。

ValueTask<TResult>

Task 和 Task<TResult> 是引用类型,由此,品质关键路线中的内部存款和储蓄器分配会对质量产生负面影响,特别当分配出今后严密循环中时。
援助通用再次回到类型意味着可再次来到轻量值类型(并不是援用类型),进而制止额外的内部存款和储蓄器分配。

使用ValueTask<TResult>,需求增加NuGet包
System.Threading.Tasks.Extensions

ValueTask<TResult> 是struct值类型,Task 和 Task<TResult>
是class援用类型

异步和等待


假若通过 async 修饰符钦点某种格局为异步方法,则能够启用以下七个效果与利益。

  • 标记的异步方法能够运用 await 来钦点悬挂点。await
    运算符文告编写翻译器异步方法唯有直到等待的异步进程一呵而就能力延续透过该点。
    同期,控件重返至异步方法的调用方。 await
    表达式中异步方法的挂起不能使该格局退出,而且 finally 块不会运维。
  • 标记的异步方法自个儿可以通过调用它的措施等待

异步方法一般包蕴 await 运算符的一个或多个相配项,但贫乏 await
表达式不会变成编写翻译器错误。 即使异步方法未使用 await
运算符标志悬挂点,则该措施将作为合办方法推行,不管异步修饰符怎么着。
编译器将为此类措施公布贰个警示。

Async 、async、Await 和 await 都是内外文关键字。
有关更加多音讯和演示,请参见以下主旨:

  • async
  • await

异步方法的特征

  • 艺术具名富含 async 修饰符。
  • 遵从约定,异步方法的名目以“Async”后缀结尾。
  • 归来类型为下列项目之一:
    • 一经您的主意有操作数为 TResult 类型的回到语句,则为
      Task<TResult>
    • 固然你的不二诀要没有回到语句或有所未有操作数的归来语句,则为
      Task
    • void:假设要编写制定异步事件管理程序。
    • 包含 GetAwaiter 方法的任何任何项目(自 C# 7.0 起)。
  • 措施一般满含至少贰个 await
    表明式,该表达式标识一个点,在该点上,直到等待的异步操作落成措施展技能能三番五次。
    同一时候,将艺术挂起,何况决定重回到点子的调用方。

有关async和await具体的试行流程,方法哪一天挂起和自由,请参谋异步程序中的调节流
(C#)

下载 Demo

发表评论

电子邮件地址不会被公开。 必填项已用*标注