Task.Factory.StartNew在ASP.Net MVC中有帮助还是有害?

时间:2021-05-26 02:16:21

I have an MVC controller action that needs to make several web requests. So in an attempt to free this thread to handle other incoming web requests I wrote something like this: (NOTE: this is an over simplification of the real code)

我有一个MVC控制器操作,需要发出几个Web请求。所以在尝试释放这个线程来处理其他传入的Web请求时,我写了这样的东西:(注意:这是对实际代码的过度简化)

public async Task<ViewResult> Index()
{
   MyObj o = await Task.Factory.StartNew<MyObj>(() =>
   {
      WebClient c = new WebClient();
      var res1 = c.DownloadString("...");
      var res2 = c.DownloadString("..."); //Not shown but res1 required for this call.
      return new MyObj(res1, res2);
   }
   return View(o);
}

My question is have I made things better or worse by spinning up a new thread to do this work. My intention is to free this .Net thread to handle other incoming requests while the network requests get made. But after looking at it seems to me I'm still making a .Net thread block, just maybe a different one from the thread pool instead of the original, so I'm really no better off. So is my suspicion correct and the above code making things worse?

我的问题是,通过启动新线程来完成这项工作,我做得更好或更糟。我的目的是释放这个.Net线程来处理网络请求时的其他传入请求。但看了之后,在我看来,我仍然在制作一个.Net线程块,只是可能与线程池不同而不是原始块,所以我真的没有好转。那么我的怀疑是否正确以及上述代码使事情变得更糟?

The benefit of Task.Factory.StartNew() if it worked... is that it simplifies the work inside from having to be done all async. My question though is: Does doing it that way in fact free a thread for handling incoming web requests or is it still tying up the same number of threads from the thread pool?

如果它工作的话,Task.Factory.StartNew()的好处就是它简化了必须完成所有异步的内部工作。我的问题是:这样做是否实际上释放了一个线程来处理传入的Web请求,或者它仍然从线程池中占用相同数量的线程?

3 个解决方案

#1


4  

Yes, you are just blocking a different thread now.

是的,你现在只是阻止一个不同的线程。

If this was good, MVC would just wrap all action methods in a new task automatically.

如果这很好,MVC会自动将所有动作方法包装在一个新任务中。

To unblock threads you need async IO somewhere under the covers. The BCL usually provides this. If it says "async" on the box it usually is async IO.

要取消阻止线程,您需要在封面下的某个地方使用异步IO。 BCL通常提供此功能。如果它在框上显示“async”,则通常是异步IO。

That said, few web apps have the problem of running out of threads. The thread-pool starts tons of threads if necessary. Very few web apps are limited in throughput by the number of threads available. Do you really need to process 100s of concurrent requests? Can your backend services even handle this load? If any of these questions is answered by "no" you don't need async.

也就是说,很少有网络应用程序存在线程耗尽的问题。如有必要,线程池会启动大量线程。很少有Web应用程序的吞吐量受可用线程数量的限制。你真的需要处理100个并发请求吗?您的后端服务甚至可以处理此负载吗?如果这些问题中的任何一个被“否”回答,则不需要异步。

#2


2  

The code you made isn't really optimal, since both long operations block each other:

您制作的代码并不是最佳,因为两个长操作都会相互阻塞:

var result1 = c.DownloadString("...");

will run first and when done, it runs

将首先运行,完成后运行

var result2 = c.DownloadString("...");

Adding an extra thread where this runs in will not improve performance, nor will it free any open requests.

在其中运行的额外线程不会提高性能,也不会释放任何打开的请求。

#3


1  

You don't need to the factory block. You can simplify your example to:

你不需要工厂区。您可以将示例简化为:

public async Task<ViewResult> Index()
{
    WebClient client = new WebClient();
    var result1 = await client.DownloadStringAsync("...");
    var result2 = await client.DownloadStringAsync("...");

    /* whatever you're doing with result1 & result2 */     

   return View();
}

#1


4  

Yes, you are just blocking a different thread now.

是的,你现在只是阻止一个不同的线程。

If this was good, MVC would just wrap all action methods in a new task automatically.

如果这很好,MVC会自动将所有动作方法包装在一个新任务中。

To unblock threads you need async IO somewhere under the covers. The BCL usually provides this. If it says "async" on the box it usually is async IO.

要取消阻止线程,您需要在封面下的某个地方使用异步IO。 BCL通常提供此功能。如果它在框上显示“async”,则通常是异步IO。

That said, few web apps have the problem of running out of threads. The thread-pool starts tons of threads if necessary. Very few web apps are limited in throughput by the number of threads available. Do you really need to process 100s of concurrent requests? Can your backend services even handle this load? If any of these questions is answered by "no" you don't need async.

也就是说,很少有网络应用程序存在线程耗尽的问题。如有必要,线程池会启动大量线程。很少有Web应用程序的吞吐量受可用线程数量的限制。你真的需要处理100个并发请求吗?您的后端服务甚至可以处理此负载吗?如果这些问题中的任何一个被“否”回答,则不需要异步。

#2


2  

The code you made isn't really optimal, since both long operations block each other:

您制作的代码并不是最佳,因为两个长操作都会相互阻塞:

var result1 = c.DownloadString("...");

will run first and when done, it runs

将首先运行,完成后运行

var result2 = c.DownloadString("...");

Adding an extra thread where this runs in will not improve performance, nor will it free any open requests.

在其中运行的额外线程不会提高性能,也不会释放任何打开的请求。

#3


1  

You don't need to the factory block. You can simplify your example to:

你不需要工厂区。您可以将示例简化为:

public async Task<ViewResult> Index()
{
    WebClient client = new WebClient();
    var result1 = await client.DownloadStringAsync("...");
    var result2 = await client.DownloadStringAsync("...");

    /* whatever you're doing with result1 & result2 */     

   return View();
}