C# Task 包含 await ConfigureAwait CancellationTokenSource

Task

C#中,TaskSystem.Threading.Tasks 命名空间中的一个类,它代表了异步操作 的执行。Task 类是异步编程模型的核心,它允许开发者编写非阻塞的代码,提高应用程序的响应性和性能。

以下是 Task 类的一些关键特性和用法:

  • 表示异步操作:Task 表示一个可能已经完成、正在运行或尚未开始的异步操作。

  • 返回值:Task<TResult>Task 的泛型版本,它表示一个异步操作,该操作将返回一个指定类型的结果。

  • 状态跟踪:Task 对象提供了属性来跟踪其状态,如 StatusIsCompletedIsFaulted 等。

  • 异常处理:如果异步操作中发生异常,Task 对象的 Exception 属性将包含异常信息。

  • 等待完成:可以使用 await 关键字或 Task.Wait()Task.Result 方法来等待 Task 完成。

  • 取消支持:Task 支持使用 CancellationToken 来取消操作。

  • 连续性:可以使用 ContinueWith 方法来安排在任务完成后执行的连续任务。

  • 并行执行:Task 可以与其他任务并行执行,使用 Task.WhenAllTask.WhenAny 来管理多个任务的完成。

以下是一些使用 Task 的示例:

创建并启动一个任务

// 创建并启动一个任务
Task task = Task.Run(() => 
{
    Console.WriteLine("Task is running on thread: " + 
    	Thread.CurrentThread.ManagedThreadId);
});
// 等待任务完成
task.Wait();

使用 await 等待任务完成

public async Task DoWorkAsync()
{
    await Task.Run(() => 
    {
        // 模拟长时间运行的任务
        Thread.Sleep(1000);
        Console.WriteLine("Work is done.");
    });
}

处理任务异常

public async Task DoWorkWithExceptionAsync()
{
    try
    {
        await Task.Run(() => 
        {
            throw new InvalidOperationException("Something went wrong!");
        });
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Caught an exception: {ex.Message}");
    }
}

使用 Task<TResult> 获取结果

public async Task<int> GetResultAsync()
{
    return await Task.Run(() => 
    {
        // 模拟计算过程
        return 42;
    });
}

取消任务

public async Task CancelTaskAsync(CancellationToken cancellationToken)
{
    var task = Task.Run(() =>
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            // 模拟长时间运行的任务
        }
    }, cancellationToken);

    await Task.Delay(100); // 模拟一段时间后取消任务
    cancellationToken.Cancel();
    await task;
}

总结

Task 类是.NET异步编程的基础,它提供了一种简单而强大的方式来编写和组织异步代码。


await

C# 中,await 关键字用于异步编程,它有几个关键作用

暂停方法执行:

当编译器遇到一个 await 表达式时,它会暂停当前 async 方法的执行,直到被 await 的任务(TaskTask<T>)完成。

非阻塞调用:

await 允许程序在等待异步操作完成时继续执行其他代码。这意味着程序可以执行其他任务,而不是被阻塞等待异步操作的完成。

任务结果获取:

await 一个 Task<T> 时,它返回任务的结果。一旦任务完成,await 表达式的结果就是 Task<T> 的结果。

异常处理:

如果 await 的任务失败并抛出异常,异常会被传播到 await 调用的地方。如果 await 被包含在一个 try 块中,异常可以被捕获和处理。

同步上下文恢复:

await 表达式可以配置为在特定的同步上下文中继续执行(例如,UI 线程)。如果 await 表达式没有指定继续执行的上下文,它将恢复到调用它的原始上下文。

配置任务继续执行的线程:

使用 await 时,可以指定一个 TaskScheduler,来决定任务完成后在哪个线程上继续执行。

组合异步操作:

await 可以与 async 一起使用,创建更复杂的异步工作流,如链式调用多个异步方法。

简化异步编程:

使用 awaitasync 可以大大简化异步代码的编写,使异步代码看起来和同步代码类似,更容易理解和维护。

下面是一个使用 await 的简单示例:

using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        int result = await GetNumberAfterDelayAsync();
        Console.WriteLine(result);
    }

    static async Task<int> GetNumberAfterDelayAsync()
    {
        await Task.Delay(1000); // 模拟异步操作,延迟1秒
        return 42; // 返回结果
    }
}

在这个示例中,Main 方法使用 await 等待 GetNumberAfterDelayAsync 方法完成,并获取它返回的整数结果。await 使得 Main 方法可以非阻塞地等待异步操作的完成。


ConfigureAwait

C#中,ConfigureAwait 是一个方法,用于配置 await 操作是否继续在原始的同步上下文上执行,或者是否继续在不同的上下文上执行。这通常在异步编程中使用,特别是在使用 Taskasync 关键字时。

当你调用一个异步方法并使用 await 时,await 会返回一个 TaskTask<T> 对象。ConfigureAwaitTask 的一个扩展方法,允许你指定是否要捕获当前的同步上下文,并在继续执行异步操作时使用它。

使用场景

通常,当你在 UI 应用程序中使用异步方法时,你可能希望在 UI 线程上继续执行,以更新 UI 元素。默认情况下,await 会尝试捕获当前的同步上下文,并在异步操作完成后返回到这个上下文。但是,如果你在一个没有 UI 线程的上下文中使用 await,或者你希望避免不必要的上下文捕获,你可以使用 ConfigureAwait(false)

语法

await someTask.ConfigureAwait(false);

参数

false:指示 await 操作不需要捕获当前的同步上下文。这意味着当异步操作完成时,它不会尝试返回到原始的上下文,这可以提高性能,尤其是在没有 UI 线程或不需要 UI 更新的情况下。

true默认值):指示 await 操作应该捕获当前的同步上下文,并在异步操作完成后返回到这个上下文。这在需要更新 UI 或访问线程绑定对象时非常有用。

示例

public async Task SomeAsyncMethod()
{
    // 执行一些异步操作
    await SomeOtherAsyncMethod().ConfigureAwait(false);

    // 继续执行其他操作,这里不会捕获原始的同步上下文
}

总结

使用 ConfigureAwait(false) 可以提高性能,特别是在高并发的环境下,因为它避免了不必要的上下文切换。然而,你应该谨慎使用它,确保不会因此而违反线程安全或 UI 更新的需求


CancellationTokenSource

CancellationTokenSourceC#中的一个类,它提供了一种机制来发出取消请求。这个类与 CancellationToken 类一起使用,允许异步操作被取消。以下是 CancellationTokenSource 的一些关键特性和用法:

  • 创建: 你可以创建一个 CancellationTokenSource 的实例来开始一个取消操作。

  • 取消: 通过调用 CancellationTokenSourceCancel 方法,你可以发出取消请求。

  • 传播取消: CancellationTokenSource 可以传播取消请求到所有与之关联的 CancellationToken 对象。

  • 超时: 你可以设置一个超时时间,如果超时时间到了,取消请求会自动发出。

  • 链接: 你可以将多个 CancellationTokenSource 实例链接在一起,这样任何一个源发出取消请求,都会传播到所有链接的源。

下面是一个使用 CancellationTokenSource 的示例:

using System;
using System.Threading;
using System.Threading.Tasks;

public class Program {
    public static void Main() {
        // 创建CancellationTokenSource
        var cts = new CancellationTokenSource();

        // 创建CancellationToken
        CancellationToken token = cts.Token;

        // 启动一个异步任务
        Task task = Task.Run(() =>
            DoLongRunningOperation(token), token);

        // 模拟用户决定取消操作
        Console.WriteLine("按任意键取消操作...");
        Console.ReadKey();

        // 发出取消请求
        cts.Cancel();

        try {
            // 等待任务完成或抛出异常
            task.Wait();
        } catch (AggregateException ae) {
            // 处理取消异常
            foreach (var e in ae.InnerExceptions) {
                if (e is OperationCanceledException) {
                    Console.WriteLine("操作已被取消。");
                }
            }
        }
    }

    private static void DoLongRunningOperation(
    	CancellationToken cancellationToken) {

        for (int i = 0; i < 10; i++) {
            // 检查是否有取消请求
            cancellationToken.ThrowIfCancellationRequested();

            // 模拟长时间的工作
            Thread.Sleep(1000);
            Console.WriteLine($"执行步骤 {i + 1}");
        }
    }
}

总结

在这个示例中,我们创建了一个 CancellationTokenSource 并从它获取了一个 CancellationToken。然后,我们启动了一个异步任务 DoLongRunningOperation,并将 CancellationToken 传递给它。当用户按下任意键时,我们调用 Cancel 方法来发出取消请求。如果任务被取消,DoLongRunningOperation 方法中的 ThrowIfCancellationRequested 将抛出 OperationCanceledException 异常,我们捕获这个异常并处理它。


个人理解

对于一个aysnc修饰的方法,没有什么特殊的,调用也是正常的按顺序执行,但是,一旦你使用了await
就会出现这样的事情:

  • 首先,由于必须在有aysnc修饰的方法中使用await
  • 于是就说明的async的作用——将方法包装成状态机,
  • 所以在执行到await时:对于主线程来说,整个状态机(async修饰的方法)都会被挂起,然后这个方法会到其他线程执行,主线程继续执行该方法之后的语句,直到await后面的语句执行完毕,
  • 最后方法从被挂起的状态回归

例子如下

using System;
using System.Threading;
using System.Threading.Tasks;

public class Program {
    public async static Task Main() {
        var cts = new CancellationTokenSource();
        CancellationToken token = cts.Token;

        try {
            DoLongRunningOperation(token);
            Console.WriteLine("Main  Thread:" + 
            	Environment.CurrentManagedThreadId);
            Thread.Sleep(500);
            cts.Cancel();

        } catch (TaskCanceledException ee) {
            Console.WriteLine(ee.Message);
        }

        Console.ReadKey();
    }

    private async static Task DoLongRunningOperation(
    	CancellationToken cancellationToken) {
        int i = 1;
        while (!cancellationToken.IsCancellationRequested) {
            Console.WriteLine("DoLo  Thread:" + 
            	Environment.CurrentManagedThreadId);
            await Task.Delay(100);
            Console.WriteLine($"{i++}");
        }
    }
}

运行结果如下

DoLo  Thread:1
Main  Thread:1
1
DoLo  Thread:4
2
DoLo  Thread:4
3
DoLo  Thread:4
4
DoLo  Thread:4
5

  • 25
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值