1.基本概念
C# 中的异步协程是一种编程模型,它允许开发者编写简洁且易于理解的异步代码。这种编程模型主要用于处理长时间运行的 I/O 操作,如文件读写、网络请求等,而不会导致线程阻塞。在C#中,异步编程主要通过async
和await
关键字实现。协程(Coroutines)在C#中通常指的是使用yield
实现的简单形式的异步编程,但从C# 5.0开始,引入了基于任务的异步编程模型(Task-Based Asynchronous Pattern, TAP),它是通过async
方法和await
运算符实现的。
2.关键词相关概念及语法:
2.1 async
关键字:
async
关键字用于修饰方法,表示该方法是一个异步方法。它允许方法内部使用 await
关键字挂起执行,而不会阻塞线程。异步方法通常返回 Task
或 Task<T>
类型,表示一个异步操作。
public async Task DoSomethingAsync()
{
// 异步操作
}
2.2 await
关键字:
await
关键字用于等待异步操作的完成。当代码执行到 await
表达式时,当前方法的剩余部分将被挂起,控制权返回给调用者。一旦异步操作完成,方法将继续执行。await
通常与 async
关键字一起使用。
public async Task AnotherAsyncMethod()
{
// 异步读取文件
string result = await ReadFileAsync("example.txt");
Console.WriteLine(result);
}
2.3 任务(Task):
Task
是一个表示异步操作的对象。它可以用来封装任何异步操作,并提供一个统一的接口来等待操作完成。Task
类型有多个衍生类型,如 Task<T>
表示返回结果的异步操作,TaskCompletionSource<T>
用于手动创建异步操作等。
2.4 异常处理
在异步协程中,异常处理与同步代码类似。当异步操作引发异常时,异常会被存储在关联的 Task
对象中。使用 try-catch
语句来捕获和处理这些异常。
public async Task HandleExceptionsAsync()
{
try
{
await FaultyAsyncMethod();
}
catch (Exception ex)
{
Console.WriteLine($"发生异常: {ex.Message}");
}
}
2.5 配置和取消:
C# 异步协程支持任务的取消和配置。使用 CancellationToken
类来传递一个取消令牌,可以在需要时取消异步操作。同时,可以使用 ContinueWith
方法来指定在任务完成后要执行的回调方法。
public async Task CancellableAsyncMethod()
{
CancellationToken token = ...;
await LongRunningAsyncOperation(token);
}
2.6 并行和连续:
C# 异步协程可以与其他并行编程模型(如 PLINQ、Task Parallel Library)结合使用,实现更高效的数据处理和任务调度。
2.7完整示例
只有当task1和task2都完成了之后才能执行下一个任务,代码如下所示:
using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace TestDemo
{
class Program
{
static void Main()
{
Console.WriteLine("主线程开始");
Task task = DoTaskAsync();
task.GetAwaiter().GetResult(); // 等待异步操作完成
Console.WriteLine("所有任务完成");
Console.ReadLine();
}
static async Task Task1()
{
await Task.Run(async () => {
for (int i = 0; i < 5; i++)
{
Console.WriteLine(i + " 开始");
//Thread.Sleep(1000);
await Task.Delay(1000); // 模拟一个耗时操作
}
});
}
static void Task2()
{
for (int i = 11; i < 20; i++)
{
Console.WriteLine(i + " 开始");
Thread.Sleep(1000);
}
}
static async Task DoTaskAsync()
{
Task p = Task1();
Task2();
await p;
}
}
}
运行结果如下所示:
3.总结
C# 异步协程的引入大大简化了异步编程的复杂性,使得开发者可以专注于业务逻辑,而不用担心底层的线程管理和同步问题。这种编程模型已经成为 C# 中处理异步操作的首选方法。