首页 > 编程语言 >C#理解async和await

C#理解async和await

时间:2024-03-22 19:01:26浏览次数:19  
标签:异步 Task C# await static 操作 async

1.async和await

在C#中,async和await是用于处理异步操作的关键字。

  • async: 用于定义一个方法是异步的。当一个方法被声明为async时,它可以包含await表达式,并且其返回类型通常是Task或Task。
  • await: 用于暂停异步方法的执行,等待异步操作的完成。在使用await关键字时,其后面的表达式通常是一个返回Task或Task的方法调用,或者其他符合异步编程模型的对象。

以下是一个简单的示例:

using System;
using System.Net.Http;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        string url = "https://api.example.com/data";
        string data = await GetDataAsync(url);
        Console.WriteLine(data);
    }
    static async Task<string> GetDataAsync(string url)
    {
        using (var client = new HttpClient())
        {
            HttpResponseMessage response = await client.GetAsync(url);
            response.EnsureSuccessStatusCode();
            return await response.Content.ReadAsStringAsync();
        }
    }
}

在这个示例中,Main方法是异步的,它调用了GetDataAsync方法并使用await等待异步操作的完成。GetDataAsync方法也是异步的,它使用HttpClient来进行异步HTTP请求,并使用await等待响应结果。

2.使用async流

在 C# 中,可以使用 async 和 await 关键字来创建异步流。通过 async/await 可以编写具有顺序执行和清晰逻辑的异步代码。
下面是一个简单的示例,演示了如何在 C# 中使用 async 和 await 创建异步流:

using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        Console.WriteLine("Start");
        await FetchData();
        Console.WriteLine("Data fetched");
        await ProcessData();
        Console.WriteLine("Data processed");
        Console.WriteLine("Async flow completed");
    }
    static async Task FetchData()
    {
        await Task.Delay(1000); // 模拟异步操作
    }
    static async Task ProcessData()
    {
        await Task.Delay(500); // 模拟异步操作
    }
}

在这个示例中,Main 方法是一个异步方法,它按顺序调用了 FetchData 和 ProcessData 方法,并使用 await 来等待它们完成。整个程序通过 async/await 得到了清晰的流程控制,使得异步操作的处理逻辑更加直观和易于理解。

3.错误处理

在异步操作中,有效的错误处理对于确保应用程序的稳定性和可靠性至关重要。以下是如何在C#中处理异步操作中的错误:

捕获异常: 在异步方法中使用try-catch块来捕获异常,并根据需要处理异常情况。如果异步方法内发生异常,该异常将被封装在Task对象中。

static async Task SomeMethod()
{
    try
    {
        // 异步操作
    }
    catch(Exception ex)
    {
        Console.WriteLine($"An error occurred: {ex.Message}");
    }
}

向上传递异常: 当在异步方法内部捕获异常后,有时需要将异常向上传递给调用者。可以使用throw语句将异常重新抛出。

static async Task<int> DivideAsync(int x, int y)
{
    try
    {
        return x / y;
    }
    catch(DivideByZeroException ex)
    {
        throw new InvalidOperationException("Divide by zero error", ex);
    }
}

AggregateException: 当同时等待多个任务完成时,可能会遇到多个异常情况。这时可以使用AggregateException来包装多个异常,以便一次性处理。

static async Task DoMultipleOperationsAsync()
{
    try
    {
        await Task.WhenAll(Operation1Async(), Operation2Async());
    }
    catch(AggregateException ex)
    {
        foreach(var innerEx in ex.InnerExceptions)
        {
            // 处理每个内部异常
        }
    }
}

通过以上方式,可以有效地处理异步操作中可能发生的异常情况,确保应用程序的健壮性。

4.取消异步操作

在异步环境中,有时候需要取消正在进行的异步操作以提高性能或避免不必要的计算。以下是在C#中取消异步操作的示例:

使用CancellationToken: 使用CancellationToken来通知异步操作应该取消。异步方法应接受一个CancellationToken参数,并在合适的地方检查IsCancellationRequested属性。

static async Task LongRunningOperationAsync(CancellationToken cancellationToken)
{
    while(!cancellationToken.IsCancellationRequested)
    {
        // 执行长时间运行的操作
    }
}

取消Token联结: 可以将多个CancellationToken链接在一起,从而实现同时取消多个异步操作。

static async Task MultipleOperationsAsync(CancellationToken token)
{
    CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(token);
    await Task.WhenAll(Operation1Async(cts.Token), Operation2Async(cts.Token));
}

取消任务: 使用Task的Cancel方法来取消尚未开始执行的异步操作。

var cts = new CancellationTokenSource();
cts.Cancel(); // 取消任务

5.并行性

在异步编程中,利用并行执行多个异步操作可以提高程序的性能和效率。以下是在C#中实现并行性的示例:

Task.WhenAll: 使用Task.WhenAll方法可以同时等待多个任务完成,而无需阻塞主线程。

static async Task MultipleOperationsAsync()
{
    Task task1 = Operation1Async();
    Task task2 = Operation2Async();
    await Task.WhenAll(task1, task2);
    // 所有任务都已完成
}

Task.WhenAny: 使用Task.WhenAny方法可以等待任意一个任务完成。

static async Task AnyOperationCompletesAsync()
{
    Task completedTask = await Task.WhenAny(LongOperation1Async(), LongOperation2Async());

    // 处理第一个完成的任务
}

Parallel.ForEach: 使用Parallel.ForEach可以实现并行迭代集合内的元素。

static void ProcessItemsInParallel(List<int> items)
{
    Parallel.ForEach(items, item =>
    {
        // 处理每个元素
    });
}

通过以上方式,可以很方便地实现并行执行多个异步操作,从而提高应用程序的性能和效率。

6.异步初始化

有时候需要在异步环境中进行一些初始化工作,例如从数据库或远程服务器加载配置数据。以下是如何在C#中实现异步初始化的示例:

在构造函数中使用async:虽然不能直接在构造函数中定义异步方法,但可以在构造函数中调用异步方法来进行初始化。

public class DataService
{
    public DataService()
    {
        InitializeAsync().Wait();  // 使用Wait()同步等待初始化完成
    }

    private async Task InitializeAsync()
    {
        // 异步初始化操作
    }
}

使用静态初始化方法:可以定义一个静态方法来执行异步初始化,并确保在使用该类之前调用该方法。

public class DataService
{
    private static bool _initialized = false;

    public static async Task InitializeAsync()
    {
        if (!_initialized)
        {
            // 异步初始化操作
            _initialized = true;
        }
    }
}

通过以上方式,可以在异步环境中有效地进行初始化工作,确保应用程序在开始执行其他操作之前完成必要的准备工作。

7.异步事件处理

在异步编程中,如何处理事件是一个重要的问题。在C#中,可以使用async和await来处理异步事件,避免在异步方法中阻塞事件循环。

异步事件处理: 定义一个异步事件处理方法,并使用await来等待异步操作的完成。

public async void Button_Click(object sender, EventArgs e)
{
    await DoSomethingAsync();
    // 在异步操作完成后执行后续逻辑
}

事件包装器: 有时候为了将同步事件包装成异步方法,可以使用TaskCompletionSource来实现。

public event EventHandler<EventArgs> MyEvent;
public Task MyEventAsync()
{
    var tcs = new TaskCompletionSource<object>();
    MyEvent += (sender, args) =>
    {
        // 执行异步操作
        tcs.SetResult(null);
    };
    return tcs.Task;
}

通过以上方式,可以在异步环境中处理事件,并确保异步方法不会阻塞事件循环。

希望以上关于异步编程的示例和解释对你有所帮助。异步操作在现代软件开发中起着重要作用,通过合理地利用async/await、错误处理、取消操作、并行性、异步初始化和异步事件处理等技术,可以编写出高效、可靠的异步代码。如果你有任何其他问题或需要进一步的帮助,请随时告诉我。祝你编写出优秀的异步代码!

标签:异步,Task,C#,await,static,操作,async
From: https://blog.csdn.net/qq_42497776/article/details/136810858

相关文章

  • C#配置网站的服务和HTTP请求管道
    在前面的文章学习了如何使用ASP.NETCoreRazorPages构建网站C#使用ASP.NETCoreRazorPages构建网站(一)C#使用ASP.NETCoreRazorPages构建网站(二)C#使用ASP.NETCoreRazorPages构建网站(三)接下来了解如何配置服务和HTTP请求管道1.配置服务(ConfigureServices)打......
  • 遥感影像问题深度学习:PyTorch在气候变化研究中的应用
    我国高分辨率对地观测系统重大专项已全面启动,高空间、高光谱、高时间分辨率和宽地面覆盖于一体的全球天空地一体化立体对地观测网逐步形成,将成为保障国家安全的基础性和战略性资源。未来10年全球每天获取的观测数据将超过10PB,遥感大数据时代已然来临。随着小卫星星座的普及,......
  • 西门子PLC常用底层逻辑块分享_模拟量写入
    文章目录前言一、功能概述二、模拟量写入程序编写1.创建自定义数据类型2.创建FC块“模拟量写入”3.编写程序前言本文分享一个自己编写的模拟量写入逻辑块。一、功能概述常用于阀门开度或者电机转速设置。二、模拟量写入程序编写1.创建自定义数据类型2.创建F......
  • [C++提高编程](一):模板----函数模板
    目录函数模板作用函数模板的语法注意事项普通函数与函数模板的区别普通函数与函数模板的调用规则模板的局限性案例--通用数组选择排序从大到小模板是C++中泛型编程的基础,一个模板就是一个创建类或函数的蓝图或者公式。函数模板作用建立一个通用函数,其函数返回值类型......
  • GPT-4引领AI新纪元,Claude3、Gemini、Sora能否跟上步伐?
    【最新增加Claude3、Gemini、Sora、GPTs讲解及AI领域中的集中大模型的最新技术】2023年随着OpenAI开发者大会的召开,最重磅更新当属GPTs,多模态API,未来自定义专属的GPT。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义,不亚于互联网和个人电脑的问世。360创始人周鸿祎认......
  • Windows中控制台(cmd)模式下运行程序卡死/挂起现象解决方案(快速编辑模式)
    最近在运行编译好的exe文件时,发现了一个现象,就是通过cmd运行exe文件或者双击执行运行exe文件,偶尔会出现程序没有执行的情况。最开始发现这个现象时,还以为是程序出现了什么Bug。后面经过网上查询才知道,原始这一切都是控制台(cmd)模式下快速编辑模式捣的鬼。可能大家平常没有接触到,......
  • ubuntu安装cuda和cudnn,并测试tensorflow和pytorch库的与cuda的兼容性(2023年版)
    lspci|grep-invidia查看nvidia设备,看到GPUgcc--version检查是否安装上gcc软件包根据官方文档指示,pipinstalltorch==1.13.1+cu117-fhttps://download.pytorch.org/whl/torch_stable.html,pipinstalltorchaudio==0.13.1+cu117-fhttps://download.pytorch.org/whl/torch......
  • 文本内容如何插入excel表格中的一列,如其他列空自动填充!
    主要功能是从文本文件中读取内容,并插入到Excel文件的特定列中(这里假设是第三列,名称为’Column3’)。以下是代码功能的具体描述:创建一个Tk窗口,布局包含两个标签分别对应Excel文件路径和文本文件路径,以及两个输入框和两个浏览按钮让用户选择文件路径。定义load_excel_file和l......
  • 幸运儿(C语言)
    前期做了1篇循环数循环数(模拟(C语言))-CSDN博客的题解,虽然看的人不是很多,但觉得能帮到一部分编程初学者和爱好者也非常不错本次做的这篇文章也是一道模拟题(难易区别不好说,感觉因人而异)问题描述n个人围成一圈,并依次编号1~n,。从编号为1的人开始,按顺时针方向每隔一人选出一个,剩......
  • C与指针1.0
    //更新中,本星期结束前,会加上一些指针习题+总结出思维导图//用途:分享,仅供参考,自己复习一.指针与地址1.指针简介定义:指针是用来访问内存的,相当于房间的房间号便于查询,提高效率内存单元的编号==地址==指针大小:4/8个字节,只要是指针变量就是,和类型无关x86(32位机器,32根总线......