简体   繁体   English

使用 C# 和 .NET,为什么运行时不会自动异步运行?

[英]With C# and .NET, why doesn't the runtime automatically operate asynchronously?

This is such a basic (read noob) question regarding the .NET async/await library but I thought I'd ask it anyhow before rewriting our api's to be awaitable.这是一个关于 .NET async/await 库的基本(阅读菜鸟)问题,但我想在重写我们的 api 以等待之前无论如何我都会问它。

The Question问题

Why wouldn't the runtime simply evaluate any given thread that has a lot of idle time and automatically operate asynchronous whenever it gets to the blocking call.为什么运行时不简单地评估任何具有大量空闲时间的给定线程,并在到达阻塞调用时自动异步操作。

Example of some routine一些例程的例子

  1. Web request to some app...对某些应用程序的 Web 请求...
  2. App starts database call...应用程序启动数据库调用...
  3. Wait for response...(idle and long)等待响应...(空闲和长时间)
  4. Receive recordset...接收记录集...
  5. Return to client...返回给客户...

If I were the runtime environment, wouldn't it be wise to simply jot down that step 3 takes a while so I should use the current thread at that point, during its idle moments, to help out other routines that would normally be waiting for our current thread to be available?如果我是运行时环境,简单地记下第 3 步需要一些时间是否明智,所以我应该在此时使用当前线程,在其空闲时刻,以帮助其他通常会等待的例程我们当前的线程可用吗?

Isn't it possible that at some point in the future we'll be able to toggle a flag in the app.config (or web.config) that says <system.runtime><asyncBehavior enableAsynchronousWhenIdle=true /></system.runtime> ?有没有可能在未来的某个时候我们能够在 app.config(或 web.config)中切换一个标志,表示<system.runtime><asyncBehavior enableAsynchronousWhenIdle=true /></system.runtime> ?

Sure it's possible but it completely breaks the current programming model.当然有可能,但它完全打破了当前的编程模型。 Before when you had a blocking call you were guaranteed that no other code would run on your thread.在您进行阻塞调用之前,您可以保证不会在您的线程上运行其他代码。 This change now allows re-entrant calls on the same thread.此更改现在允许在同一线程上重入调用。

For instance consider this case:例如考虑这种情况:

static int _processCount;
static object _lockObj = new object();

public Response ProcessRequest(Request request) {
     lock (_lockObj) {
         _processCount++;
         var savedCount = _processCount;

         // Make long running request

         if (savedCount != _processCount)
            throw new InvalidOperationException("Is my lock broken?");
     }
}

Before we allow processing requests during the long running process this code is fine, but if we allow new requests to be processed on the thread while it is making a long running request we open up the possibility of this case.在我们允许在长时间运行的过程中处理请求之前,这段代码很好,但是如果我们允许在线程上处理新请求而同时发出长时间运行的请求,我们就打开了这种情况的可能性。

  1. Process Request A处理请求 A
  2. Process Request A waits for the long running operation进程请求 A 等待长时间运行的操作
  3. The idle processing uses the thread to process Request B.空闲处理使用线程来处理请求 B。
  4. Request B enters the lock because locks have thread affinity请求 B 进入锁,因为锁具有线程关联性
  5. Request B waits for the long running operation请求 B 等待长时间运行的操作
  6. Request A returns from the long running operation and throws an exception because it's state has been corrupted.请求 A 从长时间运行的操作中返回并抛出异常,因为它的状态已损坏。

So the code needs to be written in such a way that it is aware of the reentrancy potential.因此,代码需要以能够意识到可重入潜力的方式编写。 There is no way for the Framework to know if your code will break so that change will never happen.框架无法知道您的代码是否会中断,因此永远不会发生更改。

.NET (nor any framework) isn't that smart. .NET(也不是任何框架)并不是那么聪明。 Unless you explicitly program code to run asynchronously, it has no way of knowing if any particularly code should run asynchronously.除非您明确编程代码以异步运行,否则它无法知道是否有任何特定代码应该异步运行。 It can't look at your code and say, "Oh here's some code that runs awhile and blocking the UI thread, so I should run this in a separate thread so that the UI can update."它无法查看您的代码并说:“哦,这里有一些代码运行了一段时间并阻塞了 UI 线程,所以我应该在单独的线程中运行它,以便 UI 可以更新。” As far as the framework is concerned--you intended it to operate that way--and it has no intelligence to override the way you coded into something more efficient.就框架而言——你打算让它以这种方式运行——并且它没有智能来覆盖你编码成更有效的东西的方式。

Basically because both synchronous and asynchronous approaches are useful, and sometimes blocking is fine.基本上是因为同步和异步方法都很有用,有时阻塞也很好。 Asynchrony isn't a silver bullet.异步不是灵丹妙药。

In the other hand, turning all synchronous code into asynchronous operations may break a lot of code base, both from the base class library (BCL) and third-party code, because asynchronous operations should synchronize access to shared resources and objects, and current synchronous code can be an actual bomb!另一方面,将所有同步代码变成异步操作可能会破坏很多代码库,包括基类库 (BCL) 和第三方代码,因为异步操作应该同步对共享资源和对象的访问,而当前的同步代码可以是一个真正的炸弹!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM