Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/268.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么我们需要异步任务?通过创建或重用现有线程来运行默认的WebAPI请求_C#_Async Await_Task_Webapi - Fatal编程技术网

C# 为什么我们需要异步任务?通过创建或重用现有线程来运行默认的WebAPI请求

C# 为什么我们需要异步任务?通过创建或重用现有线程来运行默认的WebAPI请求,c#,async-await,task,webapi,C#,Async Await,Task,Webapi,为什么我们需要WebApi c中的异步任务,任何默认的WebApi请求都只能通过创建或重用现有线程来运行。所以线程已经被使用了?不要混淆异步和并行 异步意味着当前线程在等待对某个I/O操作的响应时被释放。本地存储、网络请求等 并行意味着同时运行两组或多组代码。这是多线程 异步代码与多线程无关。实际上恰恰相反:异步代码的一部分好处是不需要更多的线程 例如,考虑从数据库读取数据的Web API调用。如果同时收到1000个请求,会发生什么情况 如果代码是同步编写的,那么每个请求都需要一个单独的线程。但

为什么我们需要WebApi c中的异步任务,任何默认的WebApi请求都只能通过创建或重用现有线程来运行。所以线程已经被使用了?

不要混淆异步和并行

异步意味着当前线程在等待对某个I/O操作的响应时被释放。本地存储、网络请求等

并行意味着同时运行两组或多组代码。这是多线程

异步代码与多线程无关。实际上恰恰相反:异步代码的一部分好处是不需要更多的线程

例如,考虑从数据库读取数据的Web API调用。如果同时收到1000个请求,会发生什么情况

如果代码是同步编写的,那么每个请求都需要一个单独的线程。但是ASP.NET有一个最大线程数。因此,将达到最大值,其余的请求将不得不等待,直到第一批请求中的一些完成,然后才能开始

如果代码是异步编写的,那么一旦发出数据库请求,线程就会在等待数据库响应时被释放。在等待期间,ASP.NET可以使用该线程开始处理新请求

结果是,您需要更少的线程来完成相同的工作量。这也意味着你可以用同样的资源做更多的工作


微软在这方面有一系列写得很好的文章,值得一读:。那篇文章有一个关于做早餐的类比,有助于解释异步编程的真正含义。

谢谢,Gabriel你说得对

找到更清楚的答案 从链接:

现在让我们以异步模式打开文件:

public async Task<IActionResult> GetSomeFileReallyAsync(RequestParameters p) {
    string filePath = Preprocess(p);
    byte[] data;
    using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.Asynchronous)) {
        data = new byte[fs.Length];
        await fs.ReadAsync(data, 0, data.Length);
    }

    return PostProcess(data);
}
我们现在需要多少线?现在理论上,一条线就足够了。在异步模式下打开文件时,读写将在windows重叠IO上使用

简而言之,它的工作原理是这样的:有一个类似队列的对象IO完成端口,操作系统可以在该端口上发布关于某些IO操作完成的通知。NET线程池注册一个这样的IO完成端口。每个.NET应用程序只有一个线程池,因此有一个IO完成端口

当文件以异步模式打开时,它将其文件句柄绑定到此IO完成端口。现在,当您执行ReadAsync时,在执行实际读取的同时,不会阻止此特定操作的专用线程等待读取完成。当操作系统通知.NET完成端口此文件句柄的IO已完成时-.NET线程池在线程池线程上执行continuation

现在,让我们看看在我们的场景中如何以1ms的间隔处理100个请求:

请求1进入时,我们从池中抓取线程以执行1ms的预处理步骤。然后线程执行异步读取。它不需要阻塞等待完成,因此返回池

请求2进入。我们已经在一个池中有一个线程,它刚刚完成了请求1的预处理。我们不需要额外的线程-我们可以再次使用该线程

这同样适用于所有100个请求

在处理了100个请求的预处理之后,距离第一个IO完成还有200毫秒,在这段时间内,我们的1个线程可以做更多有用的工作

IO完成事件开始到达-但我们的后处理步骤也非常短,只有1ms。再次只有一个线程可以处理所有线程

这当然是一个理想的场景,但它展示了异步IO如何帮助您保存线程,而不是异步等待


如果我们的后处理步骤不是很短,而是决定在其中执行大量CPU限制的工作,该怎么办?嗯,这将导致线程池不足。线程池将毫不延迟地创建新线程,直到它达到可配置的低水位线,您可以通过ThreadPool.GetMinThreads获得该水位线,并通过ThreadPool.SetMinThreads进行更改。达到该线程数量后,线程池将尝试等待一个繁忙线程变为空闲线程。当然,它不会永远等待,通常会等待0.5-1秒,如果没有线程空闲,它会创建一个新线程。不过,在高负载情况下,这种延迟可能会使web应用程序慢很多。因此,不要违反线程池假设-不要在线程池线程上运行长时间的CPU限制工作。

如果两个人想同时连接到您的API怎么办?还是10?他们应该等别人的请求完成后再为他们提供服务吗?对不起,我不能理解你的问题。请考虑改写。