C# 异步调用aysnc await

一、基本概念

在C#中,async和await关键字用于异步编程。异步编程允许程序在执行I/O密集型操作时不会被阻塞,从而提高程序的性能和响应性。

async关键字用于定义异步方法,表明该方法可能包含await表达式,并且可以在其执行期间异步等待其他操作的完成。
await关键字用于等待异步操作完成,它只能在async方法内使用。await表达式会挂起当前方法的执行,直到其等待的操作完成,然后恢复方法的执行。


二、使用方法调用的方式

代码如下(示例):

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

class Program
{
    static void Main(string[] args)
    {
        // 调用 test 方法,该方法是异步的,但不会阻塞主线程
        test();
        Console.WriteLine("main end..."); // 输出主函数结束的提示
        Console.ReadKey(); // 等待用户输入任意键,保持程序运行
    }

    // 异步方法 test
    static async void test()
    {
        // 异步等待 2000 毫秒(2 秒)
        await Task.Delay(2000);

        // 调用 stest 方法创建三个异步任务
        Task<int> Result0 = stest(100, 2000);
        Task<int> Result1 = stest(200, 3000);
        Task<int> Result2 = stest(300, 4000);

        // 创建一个任务列表,将三个异步任务添加到列表中
        List<Task<int>> tsklst = new List<Task<int>>();
        tsklst.AddRange(new List<Task<int>> { Result0, Result1, Result2 });

        // 输出开始执行异步任务的提示
        Console.WriteLine("delegateFuncTaskReturn has been Started {0}", 100);

        // 使用 Task.WhenAny 方法异步等待任务列表中的任意一个任务完成
        Task<int> firstCompletedTask = await Task.WhenAny(tsklst);

        // 输出异步任务完成后的提示
        Console.WriteLine("after WhenAny");
        Console.WriteLine("firstCompletedTask has been done and returned value {0}", firstCompletedTask.Result);
        Console.WriteLine("program end"); // 输出程序结束的提示
    }

    // 异步方法 stest,接受一个整数参数 input 和一个整数参数 delay
    static async Task<int> stest(int input, int delay)
    {
        // 异步等待指定的延迟时间
        await Task.Delay(delay);

        // 输出异步方法执行完成的提示,并打印输入值加 1 的结果
        Console.WriteLine("delegateFuncTaskReturn has been done and returned value {0}", input + 1);

        // 再次异步等待 1000 毫秒(1 秒)
        await Task.Delay(1000);

        // 返回输入值减去 1
        return input - 1;
    }
}

这段代码的主要逻辑是创建了三个异步任务(Result0Result1Result2),每个任务都会在一定的延迟后返回一个结果。然后,使用 Task.WhenAny 方法等待任意一个任务完成。在 test 方法中,还输出了一些提示信息以表示异步任务的启动和完成状态。

以下是代码的执行过程和输出结果的总结:

  1. 主函数 Main 开始执行,调用 test 方法。
  2. test 方法异步等待了 2000 毫秒(2 秒)。
  3. stest 方法被调用三次,每次传入不同的参数,并且每个方法内部会异步等待一定的延迟时间后返回结果。
  4. 输出了五次 “delegateFuncTaskReturn has been Started 100” 的提示信息,表示异步任务已经启动。
  5. 使用 Task.WhenAny 方法等待任意一个任务完成。
  6. 当第一个任务完成时,输出了 “after WhenAny” 的提示信息,并打印了第一个完成任务的结果。
  7. 最后输出 “program end” 表示程序执行结束。

因为 Task.WhenAny 方法会返回第一个完成的任务,所以输出结果可能会因为任务执行顺序不同而有所不同,但总体上,程序会在异步任务完成后输出相应的提示信息和结果。输出结果如下:

test start...
main end...
delegateFuncTaskReturn has been Started 100
delegateFuncTaskReturn has been done and returned value 101
after WhenAny
firstCompletedTask has been done and returned value 99
program end
delegateFuncTaskReturn has been done and returned value 201
delegateFuncTaskReturn has been done and returned value 301

三、使用lamda和异步委托的方式

代码如下(示例):

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("test2 start..."); // 输出测试开始的提示信息
        test2(); // 调用异步方法 test2
        Console.WriteLine("main end..."); // 输出主函数结束的提示信息
        Console.ReadKey(); // 等待用户输入任意键,保持程序运行
    }

    // 异步方法 test2
    static async void test2()
    {
        await Task.Delay(2000); // 异步等待 2000 毫秒(2 秒)

        // 使用 lambda 表达式定义异步委托 stest
        Func<int, int, Task<int>> stest = async (int input, int delay) =>
        {
            await Task.Delay(delay); // 异步等待指定的延迟时间
            Console.WriteLine("delegateFuncTaskReturn has been done and returned value {0}", input + 1); // 输出异步方法执行完成的提示,并打印输入值加 1 的结果
            await Task.Delay(1000); // 再次异步等待 1000 毫秒(1 秒)
            return input - 1; // 返回输入值减去 1
        };
        
        // 创建三个异步任务,每个任务传入不同的参数
        Task<int> Result0 = stest(100, 2000);
        Task<int> Result1 = stest(200, 3000);
        Task<int> Result2 = stest(300, 4000);

        List<Task<int>> tsklst = new List<Task<int>>(); // 创建任务列表
        tsklst.AddRange(new List<Task<int>> { Result0, Result1, Result2 }); // 将三个异步任务添加到列表中
        
        Console.WriteLine("delegateFuncTaskReturn has been Started {0}", 100); // 输出异步任务已经启动的提示信息

        // 使用 Task.WhenAny 方法异步等待任务列表中的任意一个任务完成
        Task<int> firstCompletedTask = await Task.WhenAny(tsklst);

        Console.WriteLine("after WhenAny"); // 输出异步任务完成后的提示信息
        Console.WriteLine("firstCompletedTask has been done and returned value {0}", firstCompletedTask.Result); // 打印第一个完成任务的结果
        Console.WriteLine("program end"); // 输出程序结束的提示信息
    }
}

这段代码与之前的代码类似,不同之处在于 test2 方法中使用了 lambda 表达式来定义异步委托 stest,而不是单独定义一个异步方法 stest

以下是代码的执行过程和解释:

  1. 主函数 Main 开始执行,调用 test2 方法。
  2. test2 方法异步等待了 2000 毫秒(2 秒)。
  3. 使用 lambda 表达式定义了一个异步委托 stest,该委托接受两个参数 inputdelay,并在内部异步等待一定的延迟时间后返回一个结果。
  4. 使用 stest 异步委托创建了三个异步任务 Result0Result1Result2,每个任务传入不同的参数。
  5. 输出了五次 “delegateFuncTaskReturn has been Started 100” 的提示信息,表示异步任务已经启动。
  6. 使用 Task.WhenAny 方法等待任意一个任务完成。
  7. 当第一个任务完成时,输出了 “after WhenAny” 的提示信息,并打印了第一个完成任务的结果。
  8. 最后输出 “program end” 表示程序执行结束。

与之前的代码相比,这段代码的主要区别在于使用了 lambda 表达式来定义异步委托,使代码更加简洁和紧凑。代码主要利用了异步方法和异步委托来实现并行执行多个任务。主要执行步骤和注释已经在代码中说明。

test2 start...
main end...
delegateFuncTaskReturn has been Started 100
delegateFuncTaskReturn has been done and returned value 101
after WhenAny
firstCompletedTask has been done and returned value 99
program end
delegateFuncTaskReturn has been done and returned value 201
delegateFuncTaskReturn has been done and returned value 301

四、稍加修改使test2变成阻塞当前线程的方法(后台阻塞,如果是UI界面不会影响UI线程响应)

代码如下(示例):

 using System;
using System.Collections.Generic;
using System.Threading.Tasks;

class Program
{

	//在main函数增加async 使之可以在test2前面加await阻塞当前这个方法,等待test2运行完成之后在运行后面的流程。
    static async Task Main(string[] args)
    {
        Console.WriteLine("test2 start..."); // 输出测试开始的提示信息
        await test2(); // 异步调用 test2 方法,并等待其完成
        Console.WriteLine("main end..."); // 输出主函数结束的提示信息
        Console.ReadKey(); // 等待用户输入任意键,保持程序运行
    }

    // 异步方法 test2,返回一个 Task<int> 对象
    static async Task<int> test2()
    {
        await Task.Delay(2000); // 异步等待 2000 毫秒(2 秒)

        // 使用 lambda 表达式定义异步委托 stest
        Func<int, int, Task<int>> stest = async (int input, int delay) =>
        {
            await Task.Delay(delay); // 异步等待指定的延迟时间
            Console.WriteLine("delegateFuncTaskReturn has been done and returned value {0}", input + 1); // 输出异步方法执行完成的提示,并打印输入值加 1 的结果
            await Task.Delay(1000); // 再次异步等待 1000 毫秒(1 秒)
            return input - 1; // 返回输入值减去 1
        };
        
        // 创建三个异步任务,每个任务传入不同的参数
        Task<int> Result0 = stest(100, 2000);
        Task<int> Result1 = stest(200, 3000);
        Task<int> Result2 = stest(300, 4000);

        List<Task<int>> tsklst = new List<Task<int>>(); // 创建任务列表
        tsklst.AddRange(new List<Task<int>> { Result0, Result1, Result2 }); // 将三个异步任务添加到列表中
        
        Console.WriteLine("delegateFuncTaskReturn has been Started"); // 输出异步任务已经启动的提示信息

        // 使用 Task.WhenAny 方法异步等待任务列表中的任意一个任务完成
        Task<int> firstCompletedTask = await Task.WhenAny(tsklst);

        Console.WriteLine("after WhenAny"); // 输出异步任务完成后的提示信息
        Console.WriteLine("firstCompletedTask has been done and returned value {0}", firstCompletedTask.Result); // 打印第一个完成任务的结果
        Console.WriteLine("program end"); // 输出程序结束的提示信息

        return 0; // 返回 0,表示方法执行完成
    }
}

这段代码利用了异步方法和异步委托来实现并行执行多个任务,并且在 Main 方法中也使用了异步特性。主要执行步骤和注释已经在代码中说明。增加await关键字使它变成阻塞的方法。
输出结果如下:

test2 start...
delegateFuncTaskReturn has been Started
delegateFuncTaskReturn has been done and returned value 101
after WhenAny
firstCompletedTask has been done and returned value 99
program end
main end...
delegateFuncTaskReturn has been done and returned value 201
delegateFuncTaskReturn has been done and returned value 301