C#异步处理方式

举报
xcLeigh 发表于 2024/11/20 12:39:23 2024/11/20
【摘要】 C#异步处理方式,在 C# 中,async和await关键字是异步编程的核心。async用于修饰一个方法,表示这个方法是异步的,并且该方法可以包含一个或多个await表达式。await用于暂停异步方法的执行,直到等待的异步操作完成。这种方式基于任务(Task)和任务<T>(Task<T>)类型,Task表示一个异步操作,Task<T>表示一个返回值类型为T的异步操作。

1.基于async和await关键字的异步编程

背景和基本原理
在 C# 中,async和await关键字是异步编程的核心。async用于修饰一个方法,表示这个方法是异步的,并且该方法可以包含一个或多个await表达式。await用于暂停异步方法的执行,直到等待的异步操作完成。这种方式基于任务(Task)和任务<T>(Task<T>)类型,Task表示一个异步操作,Task<T>表示一个返回值类型为T的异步操作。
例如,一个简单的异步方法读取文件内容可以这样写:

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

class Program
{
    static async Task Main()
    {
        string content = await ReadFileAsync("test.txt");
        Console.WriteLine(content);
    }

    static async Task<string> ReadFileAsync(string path)
    {
        using (StreamReader reader = new StreamReader(path))
        {
            return await reader.ReadToEndAsync();
        }
    }
}

在这个例子中,Main方法和ReadFileAsync方法都被标记为async。在ReadFileAsync方法中,await reader.ReadToEndAsync()暂停ReadFileAsync方法的执行,直到文件读取操作完成。当读取完成后,ReadFileAsync方法返回读取到的文件内容,然后Main方法继续执行并打印文件内容。
异常处理
当在异步方法中使用await时,异常会自然地从异步操作传播到调用者。例如,如果在ReadFileAsync方法中文件不存在,reader.ReadToEndAsync()会抛出一个异常,这个异常会在await点被重新抛出,并且可以在调用ReadFileAsync的方法(如Main方法)中使用try - catch块来捕获。

static async Task Main()
{
    try
    {
        string content = await ReadFileAsync("nonexistent.txt");
        Console.WriteLine(content);
    }
    catch (FileNotFoundException ex)
    {
        Console.WriteLine($"文件不存在: {ex.Message}");
    }
}

基于Task和Task<T>类型的异步编程(不使用await)
背景和基本原理
Task和Task<T>类型提供了一种更底层的异步操作表示方式。可以通过Task.Run方法将一个同步方法包装成一个异步任务。例如,计算一个复杂的数学函数可以这样异步执行:

using System;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        Task<double> task = Task.Run(() => CalculateValue());
        // 可以在这里执行其他操作
        double result = task.Result;
        Console.WriteLine(result);
    }

    static double CalculateValue()
    {
        // 模拟复杂的计算
        double sum = 0;
        for (int i = 0; i < 1000000; i++)
        {
            sum += Math.Sqrt(i);
        }
        return sum;
    }
}

在这个例子中,Task.Run(() => CalculateValue())创建了一个异步任务,这个任务会在后台线程中执行CalculateValue方法。task.Result属性会阻塞当前线程,直到CalculateValue方法完成并返回结果。这种方式在一些简单的场景下很有用,但如果在异步操作完成之前频繁地访问task.Result,可能会导致性能问题,因为这会导致线程阻塞。
组合多个任务
可以使用Task.WhenAll和Task.WhenAny方法来组合多个任务。Task.WhenAll会等待所有给定的任务都完成,Task.WhenAny会在给定的任务中有一个完成时就返回。例如,同时下载多个文件:

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

class Program
{
    static async Task Main()
    {
        HttpClient client = new HttpClient();
        Task<string>[] tasks = new Task<string>[3];
        tasks[0] = client.GetStringAsync("https://example.com/file1.txt");
        tasks[1] = client.GetStringAsync("https://example.com/file2.txt");
        tasks[2] = client.GetStringAsync("https://example.com/file3.txt");

        // 等待所有任务完成
        Task<string[]> allTasks = Task.WhenAll(tasks);
        string[] contents = await allTasks;
        foreach (string content in contents)
        {
            Console.WriteLine(content);
        }
    }
}

基于事件的异步模式(EAP) - 旧的异步模式(现在不推荐使用,但在旧代码中可能会遇到)
背景和基本原理
在早期的 C# 异步编程中,事件的异步模式很常见。这种模式下,一个类会提供一个异步方法(通常以Async结尾)和一个或多个事件,用于在异步操作的不同阶段(如开始、完成、出错等)进行通知。例如,一个简单的WebClient下载文件的例子:

using System;
using System.Net;

class Program
{
    static void Main()
    {
        WebClient client = new WebClient();
        client.DownloadStringCompleted += Client_DownloadStringCompleted;
        client.DownloadStringAsync(new Uri("https://example.com/file.txt"));
        Console.ReadLine();
    }

    private static void Client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
    {
        if (e.Error == null)
        {
            Console.WriteLine(e.Result);
        }
        else
        {
            Console.WriteLine($"下载出错: {e.Error.Message}");
        }
    }
}

在这个例子中,WebClient的DownloadStringAsync方法用于启动异步下载操作,当下载完成(或出错)时,会触发DownloadStringCompleted事件。在事件处理程序Client_DownloadStringCompleted中,可以处理下载的结果或错误。
缺点
这种模式的主要缺点是代码的复杂性。它需要定义事件处理程序,并且在异步操作的流程控制上不如async - await模式直观。同时,它容易出现错误,如忘记订阅事件或者在事件处理程序中没有正确地处理错误情况等。另外,这种模式在组合多个异步操作时也比较复杂,相对于Task和async - await组合方式来说,代码的可读性和可维护性较差。


     🏰 大屏可视化 带你体验酷炫大屏

     💯 神秘个人简介 带你体验不一样得介绍

     💘 为爱表白 为你那个TA,体验别致的浪漫惊喜

     🎀 酷炫邀请函 带你体验高大上得邀请


     亲,码字不易,动动小手,欢迎 点赞 ➕ 收藏,如 🈶 问题请 留言(私信或评论),博主看见后一定及时给您答复,💌💌💌


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。