关注「索引目录」公众号,获取更多干货。
异步编程需要编写能够处理长时间运行的请求(例如查询数据库、调用 API 或读取大文件)的代码,而不是仅仅停下来等待响应。异步编程
对于构建响应式应用程序至关重要。在移动应用中无需使用异步即可实现 UI 冻结,而在 Web 服务器上使用异步编程可以处理大量请求,而不会被一个缓慢的请求阻塞。
使用同步意味着主线程将被阻塞,直到完成当前任务。
而使用异步时,主线程不会被阻塞,并会立即释放资源去做其他事情。任务完成后,主线程会获取结果并继续执行。
类比:做家务
想象一下,这是一个周末,你必须在家做一些核心事情。你可能需要洗衣服,洗碗,也许你想看你最喜欢的电视剧的新一集。所以你可能首先装载洗衣机并启动洗涤循环,当机器洗衣服时,你可能会装满洗碗机并启动机器。当两台机器都在工作时,你有时间观看新剧集。
以上所有步骤都是异步执行的。这意味着你不是站在洗衣机前什么也不做直到循环结束。你刚刚开始任务,然后你就可以自由地做一些其他任务。你是主线程,通过启动每台机器,你就启动了一个任务并释放了主线程。
语法一览
这是使用上述类比的例子
您只需要了解三件主要的事情。
任务:承诺。
这个对象代表着正在进行的工作。你可以把它想象成洗衣机给我们的“收据”。它不是干净的衣服,而是干净衣服的承诺。
Task:将其用于不返回值的异步方法(如 void)。 Task<T>:将其用于确实返回值的异步方法。(例如,Task 承诺最终为您提供一个字符串)。
async:我们将此关键字
添加到方法签名(例如public async Task DoLaundry())中。它只是“解锁”了在该方法中使用 await 关键字的能力。它就像一个给编译器的信号。
await:“暂停按钮”。
这是我们需要放在任务(例如 .and )前面的操作符string result = await GetSomeDataAsync();。它实际上告诉编译器这是一个长时间运行的任务。编译器可以在这里暂停此方法,将控制权交还给调用者,之后任务完成后,它可以回到这一行继续执行。
场景:定价服务
假设您有一张火车票,并且想要计算顾客的总价。让我们考虑一下每张票都有需要计算的票价、保险费、增值税和管理费。
同步解决方案:
所以这里我们需要计算多个费用,每个费用需要几秒钟:
private int GetTicketPrice()
{
Console.WriteLine($" getting Ticket Price at {DateTime.Now}");
Thread.Sleep(TimeSpan.FromSeconds(0.5));
return 20;
}
private int GetInsurancePrice()
{
Console.WriteLine($" getting insurance Price at {DateTime.Now}");
Thread.Sleep(TimeSpan.FromSeconds(1));
return 5;
}
private int CalculateVat()
{
Console.WriteLine($" Calculating Vat at {DateTime.Now}");
Thread.Sleep(TimeSpan.FromSeconds(5));
return 1;
}
private int CalculateAdminFee()
{
Console.WriteLine($" Calculating Admin fee at {DateTime.Now}");
Thread.Sleep(TimeSpan.FromSeconds(2));
return 2;
}
我们有一个费用计算器,我添加了一个秒表来查看执行需要多长时间:
public class SyncPricingService
{
public int CalculateFees()
{
var watch = Stopwatch.StartNew();
var ticketFee = GetTicketPrice();
var insuranceFee = GetInsurancePrice();
var vatFee = CalculateVat();
var adminFee = CalculateAdminFee();
var fees = new[] { ticketFee, insuranceFee, vatFee, adminFee };
watch.Stop();
Console.WriteLine($"Total time <CalculateFees>: {watch.ElapsedMilliseconds}ms");
return fees.Sum();
}
}
稍后我们将使用同步方法计算费用,只需使用syncPricingService.CalculateFees();
以下流程将耗时 8.5 秒:
▶️可运行示例:同步费用计算器
异步解决方案:
我们再次有多个用于计算费用的函数:
private async Task<int> GetTicketPriceAsync()
{
Console.WriteLine($" getting Ticket Price at {DateTime.Now}");
await Task.Delay( TimeSpan.FromSeconds(0.5));
return 20;
}
private async Task<int> GetInsurancePriceAsync()
{
Console.WriteLine($" getting Insurance Price at {DateTime.Now}");
await Task.Delay( TimeSpan.FromSeconds(1));
return 5;
}
private async Task<int> CalculateVatAsync()
{
Console.WriteLine($" Calculating Vat at {DateTime.Now}");
await Task.Delay( TimeSpan.FromSeconds(5));
return 1;
}
private async Task<int> CalculateAdminFeeAsync()
{
Console.WriteLine($" Calculating Admin fee at {DateTime.Now}");
await Task.Delay( TimeSpan.FromSeconds(2));
return 2;
}
这是我们的这个费用计算器:
public class AsyncPricingService
{
public async Task<int> CalculateFeesAsync()
{
var watch = Stopwatch.StartNew();
var ticketFeeTask = GetTicketPriceAsync();
var insuranceFeeFeeTask = GetInsurancePriceAsync();
var vatFeeTask = CalculateVatAsync();
var adminFeeTask = CalculateAdminFeeAsync();
var fees = await Task.WhenAll( ticketFeeTask, insuranceFeeTask, vatFeeTask, adminFeeTask );
watch.Stop();
Console.WriteLine($"Total time <CalculateFeesAsync>: {watch.ElapsedMilliseconds}ms");
return fees.Sum();
}
}
稍后我们可以通过调用异步方法简单地计算费用await asyncPricingService.CalculateFeesAsync();
以下是需要 5 秒的流程:
关注「索引目录」公众号,获取更多干货。

