在 C# 中使用异步、等待、任务进行异步编程

本文关键字:异步 任务 编程 等待 | 更新日期: 2023-09-19 09:02:01

C#和.NET Framework(4.5和Core)支持使用一些本机函数,类和保留关键字进行异步编程。

在了解什么是异步编程之前,让我们使用以下控制台示例了解什么是同步编程。

示例: Asynchronous Program

static void Main(string[] args)
{
    LongProcess();
            
    ShortProcess();
}
static void LongProcess()
{
    Console.WriteLine("LongProcess Started");
    //some code that takes long execution time 
    System.Threading.Thread.Sleep(4000); // hold execution for 4 seconds
    Console.WriteLine("LongProcess Completed");
}
static void ShortProcess() {
    Console.WriteLine("ShortProcess Started");
            
    //do something here
            
    Console.WriteLine("ShortProcess Completed");    
}

Output:

LongProcess Started
LongProcess Completed
ShortProcess Started
ShortProcess Completed

在上面的示例中,LongProcess()方法是一些长时间运行的任务,例如从服务器读取文件、调用返回大量数据的 Web API 或上传或下载大文件。 执行需要更长的时间(Thread.Sleep(4000)保持它 4 秒只是为了显示较长的执行时间)。ShortProcess() 是一种在 LongProcess() 方法之后执行的简单方法。

上述程序同步执行。这意味着执行从Main()方法开始,其中它首先执行LongProcess()方法,然后执行ShortProcess()方法。在执行过程中,应用程序被阻止并变得无响应(您主要可以在基于 Windows 的应用程序中看到这一点)。这称为同步编程,在当前行完全执行之前,执行不会转到下一行。

什么是异步编程?(What is Asynchronous Programming?)

在异步编程中,代码在线程中执行,而不必等待 I/O 绑定或长时间运行的任务完成。例如,在异步编程模型中,LongProcess() 方法将在与线程池不同的线程中执行,主应用程序线程将继续执行下一条语句。

Microsoft建议Task-based Asynchronous Pattern使用asyncawait关键字和TaskTask<TResult>类在.NET Framework或.NET Core应用程序中实现异步编程。

现在让我们使用 async 关键字以异步模式重写上面的示例。

示例: Asynchronous Program

static async Task Main(string[] args)
{
    LongProcess();
    ShortProcess();
}
static async void LongProcess()
{
    Console.WriteLine("LongProcess Started");
    await Task.Delay(4000); // hold execution for 4 seconds
    Console.WriteLine("LongProcess Completed");
}
static void ShortProcess() {
    Console.WriteLine("ShortProcess Started");
            
    //do something here
            
    Console.WriteLine("ShortProcess Completed");    
}

Output:

LongProcess Started
ShortProcess Started
ShortProcess Completed
LongProcess Completed

在上面的示例中,Main() 方法由 async 关键字标记,返回类型为 Taskasync 关键字将该方法标记为异步。请注意,必须async方法链中的所有方法才能实现异步编程。因此,必须async Main() 方法才能使子方法异步。

LongProcess() 方法还标有 async 关键字,使其异步。 await Task.Delay(4000);将线程执行保持 4 秒。

现在,程序从主应用程序线程中的async Main()方法开始执行。async LongProcess() 方法在单独的线程中执行,主应用程序线程继续执行下一个语句,该语句调用ShortProcess()该方法并且不等待LongProcess()完成。

异步、等待和任务(async, await, and Task)

如果 async 方法将值返回给调用代码,请将asyncawait 一起使用并Task。我们在上面的程序中只使用了 async 关键字来演示简单的异步 void 方法。

await 关键字等待 async 方法,直到它返回值。因此,主应用程序线程会停在那里,直到收到返回值。

Task类表示异步操作,泛型类表示Task<TResult>可以返回值的操作。 在上面的示例中,我们使用了启动async操作的await Task.Delay(4000),该操作休眠 4 秒,等待将线程保留到 4 秒。

下面演示返回值的 async 方法。

示例: Async Method Returns Value

static async Task Main(string[] args)
{
    Task<int> result = LongProcess();
    ShortProcess();
    var val = await result; // wait untile get the return value
    Console.WriteLine("Result: {0}", val);
    Console.ReadKey();
}
static async Task<int> LongProcess()
{
    Console.WriteLine("LongProcess Started");
    await Task.Delay(4000); // hold execution for 4 seconds
    Console.WriteLine("LongProcess Completed");
    return 10;
}
static void ShortProcess()
{
    Console.WriteLine("ShortProcess Started");
    //do something here
    Console.WriteLine("ShortProcess Completed");
}

Output:

LongProcess Started
ShortProcess Started
ShortProcess Completed
LongProcess Completed
Result: 10

在上面的示例中,在静态async Task<int> LongProcess()方法中,Task<int>用于指示返回值类型 int。 int val = await result;将在那里停止主线程,直到它获得结果中填充的返回值。 一旦获得 result 变量中的值,它就会自动将一个整数分配给 val

async方法应返回 voidTaskTask<TResult> ,其中 TResultasync 方法的返回类型。 返回void通常用于事件处理程序。async 关键字允许我们在方法中使用 await 关键字,以便我们可以等待异步方法完成依赖于返回值的其他方法。

如果您有多个返回值的async方法,则可以在后续步骤中使用返回值之前对所有方法使用 await

示例: Async Methods

static async Task Main(string[] args)
{
    Task<int> result1 = LongProcess1();
    Task<int> result2 = LongProcess2();
    
    //do something here
    Console.WriteLine("After two long processes.");
    int val = await result1; // wait untile get the return value
    DisplayResult(val);
    val = await result2; // wait untile get the return value
    DisplayResult(val);
    Console.ReadKey();
}
static async Task<int> LongProcess1()
{
    Console.WriteLine("LongProcess 1 Started");
    await Task.Delay(4000); // hold execution for 4 seconds
    Console.WriteLine("LongProcess 1 Completed");
    return 10;
}
static async Task<int> LongProcess2()
{
    Console.WriteLine("LongProcess 2 Started");
    await Task.Delay(4000); // hold execution for 4 seconds
    Console.WriteLine("LongProcess 2 Completed");
    return 20;
}
static void DisplayResult(int val)
{
    Console.WriteLine(val);
}

Output:

LongProcess 1 Started
LongProcess 2 Started
After two long processes.
LongProcess 2 Completed
LongProcess 1 Completed
10
20

在上面的程序中,我们确实等待结果 1 并等待结果 2,就在我们需要将返回值传递给另一个方法之前。

因此,您可以使用 async、await 和 Task 在 .NET Framework 或 .NET Core 中使用 C# 实现异步编程。


本文内容总结: