做网站需要什么内容,灌云县建设局网站,网站建设论文的结论,Wordpress翻译文章在.NET Framework 4.5中#xff0c;async / await关键字已添加到该版本中#xff0c;简化多线程操作#xff0c;以使异步编程更易于使用。为了最大化利用资源而不挂起UI#xff0c;你应该尽可能地尝试使用异步编程。虽然async / await让异步编程更简单#xff0c;但是有一… 在.NET Framework 4.5中async / await关键字已添加到该版本中简化多线程操作以使异步编程更易于使用。为了最大化利用资源而不挂起UI你应该尽可能地尝试使用异步编程。虽然async / await让异步编程更简单但是有一些你可能不知道的细节和注意的地方 新关键字微软在.NET框架中添加了async和await关键字。但是使用它们方法的返回类型应为Task类型。我们将在稍后讨论例外情况为了使用await关键字您必须在方法定义中使用async。如果你在方法定义中放入async你应该在主体方法的某个地方至少有一处await关键字如果你缺少他你通常会收到Visual Studio的一个警告。以下是代码中的示例 public async Task ExecuteAsync(UpdateCarCommand request, CancellationToken token default) { using (var context _contextFactory.Create()) { var entity context.Cars.FirstOrDefault(a a.Id request.Id); // Mapping logic await context.SaveChangesAsync(token); } }如果要从异步方法返回某些内容可以使用Task的泛型。像以下这样如果你想返回受影响的行数 public async Taskint ExecuteAsync(UpdateCarCommand request, CancellationToken token default) { using (var context _contextFactory.Create()) { var entity context.Cars.FirstOrDefault(a a.Id request.Id); // Mapping logic return await context.SaveChangesAsync(token); } }async.await给我们带来了什么虽然使用这个看起来很简单但是它有什么帮助呢?最后所有这些操作都是在等待数据库返回结果时(在本例中)让其他请求使用当前线程。当您向数据库、磁盘、internet等外部源发出可能需要一段时间才能运行的请求时我们可以使用async/ wait让其他请求使用这个线程。这样我们就不会有空闲的“worker”(线程)在那里等待完成其他任务。这就像去快餐店一样在你点完菜之后其他人不会点任何东西直到你吃完为止。使用async/ await其他人可以在你点完菜之后下他们的订单并且可以同时处理多个订单。它不能做什么这里需要注意的一件事是async/await并不是并行/多核编程。当您使用async/await时只处理该线程并让其他线程使用它。代码的作用类似于“同步”因为您可以在await之后以本方法继续执行代码。因此如果在一个方法中有四个await则必须等到每个方法都完成后才能调用下一个方法。因此您必须使用任务库或任何您喜欢的方法生成新线程以使它们并行运行。但是您也可以让每个线程使用async/wait这样它们就不会阻塞资源了! ConfigureAwait(false)能做什么呢默认情况下当您使用async/await时它将在开始请求的原始线程上继续运行(状态机)。但是如果当前另一个长时间运行的进程已经接管了该线程那么你就不得不等待它完成。要避免这个问题可以使用ConfigureAwait的方法和false参数。当你用这个方法的时候这将告诉Task它可以在任何可用的线程上恢复自己继续运行而不是等待最初创建它的线程。这将加快响应速度并避免许多死锁。但是这里有一点点损失。当您在另一个线程上继续时线程同步上下文将丢失,因为状态机改变。这里最大的损失是你会失去归属于线程的Culture和Language其中包含了国家语言时区信息以及来自原始线程的HttpContext.Current之类的信息因此如果您不需要以此来做多语系或操作任何HttpContext类型设置则可以安全地进行此方法的调用。注意如果需要language/culture可以始终在await之前存储当前相关状态值然后在await新线程之后重新应用它。 以下是ConfigureAwait(false)的示例 public async Taskint ExecuteAsync(UpdateCarCommand request, CancellationToken token default) { using (var context _contextFactory.Create()) { var entity context.Cars.FirstOrDefault(a a.Id request.Id); // Mapping logic return await context.SaveChangesAsync(token).CongifureAwait(false); } }注意事项同步 --异步如果要使用async/await需要注意一些事情。您可能遇到的最大问题是处理异步方法请求同步方法。如果你开发一个新项目通常可以将async/await从上到下贯穿于整个方法链中而不需要做太多工作。但是如果你在外层是同步的并且必须调用异步库那么就会出现一些有隐患的操作。如果一不小心便会引发大批量的死锁如果有同步方法调用异步方法,则必须使用ConfigureAwait(false)。如果不这样做就会立即掉进死锁陷阱。发生的情况是主线程将调用async方法最终会阻塞这个线程直到那个async方法完成。然而一旦异步方法完成它必须等待原始调用者完成后才能继续。他们都在等待对方完成而且永远不会。通过在调用中使用configurewait (false) async方法将能够在另一个线程上完成自己操作而不关心自己的状态机的位置并通知原始线程它已经完成。进行这个调用的最佳实践如下:[HttpPut]
public IActionResult Put([FromBody]UpdateCommand command) _responseMediator.ExecuteAsync(command).ConfigureAwait(false).GetAwaiter().GetResult();.NET Standard与ConfigureAwait(false)在.NETCore中微软删除了导致我们在任何地方都需要ConfigureAwait(false)的SynchronizationContext。因此ASP.NETCore应用程序在技术上不需要任何ConfigureAwait(false)逻辑因为它是多余的。但是如果在开发有一个使用.NETStandard的库那么强烈建议仍然使用.ConfigureAwait(false)。在.NETCore中这自动是无效的。但是如果有.NETFramework的人最终使用这个库并同步调用它那么它们将会遇到一堆麻烦。但是随着.NET5是由.NETCore构建的所以未来大多都是.NetCore调用.Netstadard你如果不准备让.NetFramework调用你的standard库大可不必兼容。 ConfigureAwait(false) 贯穿始终如果同步调用有可能调用您的异步方法那么在整个调用堆栈的每个异步调用上您都将被迫设置. configureAwait (false) !如果不这样做就会导致另一个死锁。这里的问题是每个async/ await对于调用它的当前方法都是本地的。因此调用链的每个异async/await都可能最终在不同的线程上恢复。如果一个同步调用一路向下遇到一个没有configurewait(false)的任务那么这个任务将尝试等待顶部的原始线程完成然后才能继续。虽然这最终会让你感到心累因为要检查所有调用是否设置此属性。 开销虽然async/ await可以极大地增加应用程序一次处理的请求数量但是使用它是有代价的。每个async/ await调用最终都将创建一个小状态机来跟踪所有信息。虽然这个开销很小但是如果滥用async/ await则会导致速度变慢。只有当线程不得不等待结果时才应该等待它。 Async Void虽然几乎所有的async / await方法都应返回某种类型的Task但此规则有一个例外有时您可以使用async void。但是当您使用它时调用者实际上不会等待该任务完成后才能恢复自己。它实际上是一种即发即忘的东西。有两种情况你想要使用它。 第一种情况是事件处理程序如WPF或WinForms中的按钮单击。默认情况下事件处理程序的定义必须为void。如果你把一个任务放在那里程序将无法编译并且返回某些东西的事件会感觉很奇怪。如果该按钮调用异步async则必须执行async void才能使其正常工作。幸运的是这是我们想要的因为这种使用不会阻塞UI。 第二个是请求你不介意等待获得结果的东西。最常见的示例是发送日志邮件但不想等待它完成或者不关心它是否完成。 然而对于这两种情况都有一些缺点。首先调用方法不能try/catch调用中的任何异常。它最终将进入AppDomain UnhandledException事件。不过如果在实际的async void方法中放入一个try catch就可以有效地防止这种情况发生。另一个问题是调用者永远不会知道它何时结束因为它不返回任何东西。因此如果你关心什么时候完成某个Task那么实际上需要返回一个Task。 探讨.NetCore中异步注意事项在.NetCore中已经剔除了SynchronizationContext剔除他的主要原因主要是性能和进一步简化操作在.NetCore中我们不用继续关心异步同步混用情况下是否哪里没有设置ConfigureAwait(false) 会导致的死锁问题因为在.netcore中的async/await 可能在任何线程上执行并且可能并行运行以下代码为例private HttpClient _client new HttpClient(); async TaskListstring GetBothAsync(string url1, string url2)
{ var result new Liststring(); var task1 GetOneAsync(result, url1); var task2 GetOneAsync(result, url2); await Task.WhenAll(task1, task2); return result;
} async Task GetOneAsync(Liststring result, string url)
{ var data await _client.GetStringAsync(url); result.Add(data);
}它下载两个字符串并将它们放入一个List中。此代码在旧版ASP.NET(.NetFramework)中工作正常由于请求处设置了await,请求上下文一次只允许一个连接.其中result.Add(data)一次只能由一个线程执行因为它在请求上下文中执行。但是这个相同的代码在ASP.NET Core上是不安全的; 具体地说该result.Add(data)行可以由两个线程同时执行而不保护共享Liststring。所以在.Netcore中要特别注意异步代码在并行执行情况下引发的问题参考:https://stackoverflow.com/questions/31186354/async-await-where-is-continuation-of-awaitable-part-of-method-performed