C# 和 .NET Framework(4.5 和核心)支持使用一些本机函数、类和保留关键字的异步编程。

在我们了解什么是异步编程之前,让我们通过下面的控制台示例来了解什么是同步编程。

示例:异步程序
 Copy
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");    
}
输出:
LongProcess Started
LongProcess Completed
ShortProcess Started
ShortProcess Completed

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

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

什么是异步编程?

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

Microsoft 建议使用基于任务的异步模式在 .NET Framework 或 .NET Core 应用程序中使用asyncawait关键字和TaskTask<TResult>类  来实现异步编程。

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

示例:异步程序
 Copy
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");    
}
输出:
LongProcess Started
ShortProcess Started
ShortProcess Completed
LongProcess Completed

在上面的例子中,Main()方法是用async关键字标记的,返回类型是Task. 关键字将该async方法标记为异步。注意方法链中的所有方法都必须是async为了实现异步编程。所以,Main()方法一定async要让子方法异步。

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

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

异步、等待和任务

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

await关键字等待该 方法async,直到它返回一个值。所以主应用程序线程停在那里,直到它收到一个返回值。

Task类表示异步操作, Task <TResult>泛型类表示可以返回值的操作。在上面的示例中,我们使用await Task.Delay(4000)了已启动async的操作,该操作会休眠 4 秒,并且 await 会持有一个线程直到 4 秒。

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

示例:异步方法返回值
 Copy
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");
}
输出:
LongProcess Started
ShortProcess Started
ShortProcess Completed
LongProcess Completed
Result: 10

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

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

如果您有多个async返回值的方法,那么您可以await在要在进一步步骤中使用返回值之前使用所有方法。

示例:异步方法
 Copy
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);
}
输出:
LongProcess 1 Started
LongProcess 2 Started
After two long processes.
LongProcess 2 Completed
LongProcess 1 Completed
10
20

在上面的程序中,我们在需要将返回值传递给另一个方法之前执行了 await result1 和 await result2。

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

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐