C# ASP.Net页面或异步页面中基于任务的编程是首选方法吗

C# ASP.Net页面或异步页面中基于任务的编程是首选方法吗,c#,asp.net,multithreading,task-parallel-library,C#,Asp.net,Multithreading,Task Parallel Library,我在一个非异步页面中使用以下基于任务的编程(TPL) 我的问题是:使用TPL(即任务并行库)在ASP.Net页面中创建多线程调用可以吗,还是必须始终使用内置异步页面功能在ASP.Net页面中创建多线程?到目前为止,TPL方法没有产生任何问题,但我只是想确定一下,万一我在ASP.Net页面中使用TPL时遗漏了一些重要的要点/隐藏的风险 Task.Factory.StartNew(() => { try

我在一个非异步页面中使用以下基于任务的编程(TPL)

我的问题是:使用TPL(即任务并行库)在ASP.Net页面中创建多线程调用可以吗,还是必须始终使用内置异步页面功能在ASP.Net页面中创建多线程?到目前为止,TPL方法没有产生任何问题,但我只是想确定一下,万一我在ASP.Net页面中使用TPL时遗漏了一些重要的要点/隐藏的风险

       Task.Factory.StartNew(() =>
                {
                    try
                    {
                        Method1(); 
                        success4 = true;
                    }
                    catch (Exception e4)
                    {
                        success4 = false;
                        ex = e4.ToString();
                    }
                }),
                Task.Factory.StartNew(() =>
                {
                    try
                    {
                        Method2();
                        success5 = true;
                    }
                    catch (Exception e5)
                    {
                        success5 = false;
                        ex = e5.ToString();
                    }
                }),
                Task.Factory.StartNew(() =>
                {
                    try
                    {
                        Method3();
                        success6 = true;
                    }
                    catch (Exception e6)
                    {
                        success6 = false;
                        ex = e6.ToString();
                    }
                })
            };
   Task.WaitAll(tasks);
更新1:

正如回答中指出的,在ASP.Net中使用TPL会限制ASP.Net应用程序的可伸缩性,因为每个任务都使用ASP.Net线程池中的一个线程,同时保持页面的原始线程处于阻塞状态。
我现在正在考虑在异步页面中调用方法时使用TPL,如下面的代码所示,以利用并行带来的更强大的处理能力。但我将进一步研究这一点,看看在实际情况下,TPL是否会使异步方法变得更好或更糟

private void DoTask4(object[] paras)
    {
        Parallel.Invoke(() =>
            {
               try
               {
                   Method4( paras);
               }
               catch (Exception e4)
               {
                   success4 = false;
                   //log the exception
               }
           });
    }

    IAsyncResult BeginAsyncOperation4(object sender, EventArgs e, AsyncCallback cb, object state)
    {
        task4 = new AsyncTaskDelegate(DoTask4);
        IAsyncResult result = task4.BeginInvoke(state as object[], cb, "task4");
        return result;
    }

    void EndAsyncOperation4(IAsyncResult ar)
    {
        task4.EndInvoke(ar);
        if (success4 == null)
        {
            success4 = true;
        }
    }

    void TimeoutAsyncOperation4(IAsyncResult ar)
    {
        success4 = false;
    }
更新2:

最后,正如回答中指出的,即使使用带有异步页面方法的TPL,也会导致线程池中的线程被使用,这再次意味着我们的ASP.Net可伸缩性将是一个问题。
因此,最好不要在异步页面中使用TPL。

这种方法可能会严重损害服务器的可伸缩性,因为它使用额外的线程并阻塞请求线程。假设
Method1..3
负责一些IO绑定的工作。如果不能使用异步ASP.NET控制器,您仍然可以使用
AsyncManager
(例如,like)或(对于经典ASP.NET)启动异步IO绑定操作,并避免阻塞

但是,如果您需要做一些CPU绑定的工作(与IO绑定的工作相反),只需在同一请求线程上一步一步地做,而不是并行地做。否则,每个
Task.Factory.StartNew
可能会搁置另一个传入的HTTP请求,具体取决于服务器负载。因为您可能希望提供尽可能多的并发HTTP请求,所以应该避免并行化CPU受限的工作


也就是说,对于并发HTTP请求数较少的intranet web应用程序,您的代码可能很好。如果您想加快对单个请求的响应传递,您可以这样做。

应该可以,您使用的是纯asp.net还是mvc?嗯,
Task.WaitAll
远远不够理想。您可能导致至少一个线程在该调用中停滞等待,而没有完成任何有用的工作(假设在调用时所有任务都已开始在其他线程上运行)。@NedStoyanov,我使用的是ASP.NET WebForms,而不是MVC。@Damien_不信者,如果我注释掉Task.WaitAll代码,页面最终会在发送响应到浏览器之前等待吗?我在哪里可以跟踪每个线程的成功/失败?太好了。因此,对ASP.Net页面使用async='true'的异步页面是实现可伸缩性的方法。由于Task.Factory会从ASP.Net线程池中提取线程,而不会放弃原始页面线程,因此,如果是,则会限制高流量场景中的可伸缩性。谢谢你澄清这一点。如果我在异步页面中调用异步方法时使用Parallel.Invoke,您认为这会有所帮助,因为异步方法将使用多个处理器,而不仅仅是一个处理器?@Sunil,我认为使用
Parallel.Invoke
也会产生与使用线程池相同的效果(根据实际CPU内核的数量,它可能会以更聪明的方式实现这一点)。此外,
Parallel.Invoke
也会阻止调用线程。好的。因此,使用异步页面方法的TPL不是一个好主意。再次感谢您澄清这一点。@Sunil,与EF6不同,EF4没有异步API。因此,只需根据需要在请求线程上调用它,而无需使用
Task.Factory.StartNew
。是的,这就是我的代码中的内容。\n哦,谢谢你的详细解释。