• C# 异步操作汇总


    在C#中,异步操作(Asynchronous Operations)可以提高程序的性能和响应能力。通常情况下,程序会等待某个操作完成之后才会继续执行下一个操作,这会导致程序的运行速度变慢。而异步操作可以让程序在等待某个操作完成的同时,执行其他操作,从而提高程序的运行效率。

    在C#中,实现异步操作的方式有以下几种:

    1.使用异步方法

    C# 5.0引入了异步方法(Async Methods)的概念,使得编写异步代码变得更加容易。异步方法使用async关键字标记,返回类型必须是Task或Task,方法中使用await关键字来等待异步操作完成。

    以下是一个使用异步方法实现异步操作的示例:

    public async Task<int> DownloadFileAsync(string url, string savePath)
    {
        using (var httpClient = new HttpClient())
        {
            var response = await httpClient.GetAsync(url);
            using (var fileStream = new FileStream(savePath, FileMode.Create))
            {
                await response.Content.CopyToAsync(fileStream);
            }
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在上面的示例中,DownloadFileAsync方法使用async关键字标记,返回类型是Task。方法中使用await关键字等待HttpClient.GetAsync和Stream.CopyToAsync方法完成异步操作。

    2.使用Task.Run方法

    Task.Run方法可以在新的线程上执行代码,因此也可以用来实现异步操作。使用Task.Run方法需要传入一个委托,该委托中的代码将在新的线程上执行。

    以下是一个使用Task.Run方法实现异步操作的示例:

    public async Task<int> DownloadFileAsync(string url, string savePath)
    {
        await Task.Run(() =>
        {
            using (var httpClient = new HttpClient())
            {
                var response = httpClient.GetAsync(url).Result;
                using (var fileStream = new FileStream(savePath, FileMode.Create))
                {
                    response.Content.CopyToAsync(fileStream).Wait();
                }
            }
        });
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在上面的示例中,DownloadFileAsync方法使用await关键字等待Task.Run方法执行的委托完成异步操作。

    3.使用TaskCompletionSource类

    TaskCompletionSource类可以用来创建一个可以异步完成的任务,然后通过SetResult或SetException方法来完成任务。使用TaskCompletionSource类需要手动编写异步代码。

    以下是一个使用TaskCompletionSource类实现异步操作的示例:

    public static Task<string> GetResultAsync()
    {
        var tcs = new TaskCompletionSource<string>();
        SomeMethod(result => tcs.SetResult(result));
        return tcs.Task;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这个示例的作用是,异步获取一个字符串结果。它使用了 TaskCompletionSource 类来创建一个 Task 对象,并在回调方法中将结果传递给该对象。

    以下是重写后的示例,更加简洁易懂:

    public static async Task<string> GetResultAsync()
    {
        return await Task.Run(() => SomeMethod());
    }
    
    • 1
    • 2
    • 3
    • 4

    在这个示例中,使用了 Task.Run 方法来将 SomeMethod 方法包装成一个 Task 对象,并通过 await 关键字来等待该对象的完成。

    相比于使用 TaskCompletionSource 类来手动管理异步操作,使用 Task.Run 方法和 await 关键字更加简洁和易懂。同时,它也能够充分利用 .NET Framework 4.5 引入的异步编程模型,更好地利用系统资源,提高程序的性能和响应速度。

    4.使用async和await异步编程

    async和await是.NET Framework 4.5引入的一种新的异步编程模型,它基于Task和Task,使异步编程更加简单和直观。使用async和await可以让程序员专注于异步操作的逻辑,而不是繁琐的状态管理和线程调度。

    以下是使用async和await编写一个简单异步操作的示例:

    public async Task<int> AsyncMethodAsync(int arg)
    {
        int result = await Task.Run(() =>
        {
            return arg * 2; // 异步操作
        });
     
        return result; // 返回异步操作的结果
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    5.使用Parallel类进行并行编程

    Parallel类是.NET Framework提供的一种用于执行并行操作的工具类,它提供了一些方法,可以让程序员轻松地编写并行操作,以提高程序的性能和效率。

    以下是使用Parallel类执行并行操作的示例:

    public int[] ParallelMethod(int[] arr)
    {
        Parallel.For(0, arr.Length, i =>
        {
            arr[i] = arr[i] * 2; // 并行操作
        });
     
        return arr; // 返回并行操作的结果
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    区别:

    这几种异步编程方法都可以实现异步操作,但它们之间存在一些差异:

    BeginInvoke/EndInvoke方式是.NET Framework较早期的异步编程模型,适用于.NET Framework 1.1和2.0版本,它需要使用委托和回调函数进行异步操作的管理和完成。但是它比较繁琐,难以理解和维护,因此已经逐渐被Task和async/await方式所取代。
    Task和Task方式是.NET Framework 4.0引入的一种新的异步编程模型,它更加灵活和直观,可以方便地管理和控制异步操作的状态和结果。使用Task和Task可以轻松地实现异步操作的取消、

    6.通过事件(Event)异步调用

    使用事件机制也是一种实现异步编程的方式。这种方式的核心思想是,调用者注册一个事件处理程序,然后异步操作执行完毕时,会调用该事件处理程序并传递操作结果。

    以下是使用事件实现异步编程的示例代码:

    public class AsyncOperation
    {
        public event EventHandler Completed;
     
        public void Start()
        {
            // 模拟异步操作
            Task.Delay(1000).ContinueWith(task => {
                OnCompleted(new EventArgs());
            });
        }
     
        protected virtual void OnCompleted(EventArgs e)
        {
            Completed?.Invoke(this, e);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    // 调用异步操作
    var operation = new AsyncOperation();
    operation.Completed += (sender, e) => {
        Console.WriteLine("异步操作完成!");
    };
    operation.Start();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    7.使用异步委托(Async delegate)

    使用异步委托也是一种实现异步编程的方式。异步委托是指一个返回类型为 Task 或 Task 的委托,可以使用 async 和 await 关键字来异步调用。

    以下是使用异步委托实现异步编程的示例代码:

    public class AsyncOperation
    {
        public async Task<int> StartAsync()
        {
            // 模拟异步操作
            await Task.Delay(1000);
            return 42;
        }
    }
    // 调用异步操作
    var operation = new AsyncOperation();
    var result = await operation.StartAsync();
    Console.WriteLine($"异步操作完成,结果为:{result}");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    使用异步委托的好处是可以在调用方使用 await 关键字来等待异步操作完成,并且可以直接获取异步操作的结果。

    8.使用异步的 LINQ(LINQ with async)

    LINQ(Language Integrated Query)是 C# 的一种语言特性,可以方便地进行数据查询和转换操作。在 .NET Framework 4.5 中,引入了一些新的异步操作符,使得 LINQ 查询可以以异步方式进行。

    以下是使用异步的 LINQ 实现异步编程的示例代码:

    var numbers = Enumerable.Range(1, 10);
     
    // 异步筛选出偶数
    var evenNumbers = await Task.Run(() => numbers.Where(n => n % 2 == 0));
     
    Console.WriteLine("筛选出的偶数为:");
    foreach (var number in evenNumbers)
    {
        Console.WriteLine(number);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    使用异步的 LINQ 可以简化代码,并且可以在查询操作比较耗时的情况下提高程序的性能。

    区别和选择

    上面介绍了几种常用的异步编程方式,每种方式都有自己的优缺点,适用于不同的场景。下面是它们之间的一些区别和选择:

    通过委托实现异步编程,适用于简单的异步操作,调用方只需要等待异步操作完成即可,不需要对结果进行处理。

    使用 Task 或 Task 类。Task 和 Task 是 .NET 框架中的一部分,是异步编程的基本构建块。它们可以用于创建异步操作、处理异步结果和执行连续异步操作。

    Task 是一个代表异步操作的类,它没有返回值。Task 是一个代表异步操作的类,它返回一个 T 类型的值。使用 Task 或 Task 可以很方便地执行异步操作,因为它们可以与 async 和 await 关键字一起使用,从而使异步代码看起来像同步代码。

    以下是使用 Task 和 Task 的示例:

    // 使用 Task 执行异步操作
    public async Task DoAsyncOperation()
    {
        await Task.Run(() =>
        {
            // 异步操作代码
        });
    }
     
    // 使用 Task 执行异步操作并返回结果
    public async Task<string> DoAsyncOperationWithResult()
    {
        var result = await Task.Run(() =>
        {
            // 异步操作代码
            return "result";
        });
     
        return result;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在上面的示例中,DoAsyncOperation 和 DoAsyncOperationWithResult 方法都使用 Task 或 Task 类来执行异步操作。它们使用 await 关键字等待异步操作完成,然后返回结果(如果有)。

    Task 和 Task 的区别在于 Task 可以返回一个值,而 Task 不可以。另外,Task 和 Task 之间的其他区别与使用 async/await 关键字的异步方法和异步 Lambda 表达式的区别类似。在执行异步操作时,Task.Run 方法是最常用的方法之一,因为它允许您在一个新的线程上执行操作。

    await Task.Run(() =>
    {
        // 异步操作代码
    });
    
    • 1
    • 2
    • 3
    • 4

    上面的代码将在一个新的线程上执行异步操作。在这种情况下,Task.Run 返回一个 Task 对象,该对象代表异步操作。由于使用了 async 和 await 关键字,所以可以等待异步操作完成,然后继续执行其他代码。

    使用 Task 或 Task 的主要优点是,它们提供了一种更灵活的方式来执行异步操作,因为它们允许您在异步操作完成之前执行其他代码。此外,Task.Run 方法可以让您在单独的线程上执行操作,这使得异步编程更容易。但是,由于 Task.Run 创建了新的线程,所以使用 Task.Run 可能会增加应用程序的负载。因此,应该根据具体情况谨慎使用 Task.Run。

  • 相关阅读:
    对vue的mixin的理解,有什么应用场景?面试题!!!
    九、Redis事务锁机制、连接池
    Git基础指令(图文详解)
    Selenium02
    YOLOv8 多种任务网络结构详细解析 | 目标检测、实例分割、人体关键点检测、图像分类
    dijkstra算法:堆优化 + 输出所有最短路径(得到所有最优解)
    使用Python实现批量删除MYSQL数据库的全部外键
    JS实现视频录制-以Cesium为例
    Git --》分支操作与团队协作
    什么是云计算?云计算简介
  • 原文地址:https://blog.csdn.net/gzylongxingtianxia/article/details/136451812