2010-09-25 61 views
6

我想在我的ASP淨MVC應用程序中實現這樣的邏輯:ASP.NET MVC多線程

user clicks a button - >

server executes some time-consuming logic in ~15 threads (i get data from really slow independent sources) - >

when all work is done, server merges the results and passes it back to user 

有一天,我看到一篇文章解釋了爲什麼在asp-net應用程序中創建新的線程是高度不推薦的,並且ThreadPool是應該使用的。 這種情況下mvc的最佳做法是什麼?爲什麼我不應該創建自己的線程,背景工作者,任務,並使用線程池?如果有問題,該應用程序將託管在公共服務器上。

回答

4

如果您使用.Net 4,我甚至會建議查看並行命名空間。他們使這更簡單,並更好地利用所有CPU核心。

我也會看看從你的主要web應用程序卸載這一切。擁有一組單獨的服務或消息隊列來處理這個長時間運行的請求,可以讓您更輕鬆地進行擴展,並允許您的Web應用程序擔心服務頁面請求,而不是執行長時間運行的邏輯。谷歌起來像「iis長期運行請求」開始。

3

因爲一個線程池的設計做到這一點:

它提供了可用於執行任務,崗位工作項目線程池,處理異步I/O,等待代表其他線程,和處理計時器。

我想最好是在服務器完成時將結果存儲在數據庫中。

然後你可以使用一個定時器和AJAX,如果製造工藝,以週期性地請求,如果是的話,得到的數據。

3

你不應該創建自己的線程,因爲這有顯著的開銷。創建一個新線程很昂貴。所以問題應該是:爲什麼你不應該使用線程池?它有許多線程可供使用。更好的方法是使用任務並行庫,它在線程池上方提供了一個抽象層,使得使用線程更容易。

你應該認識到,唯一的(簡單)的方式來做到這一點,是直到所有工作完成,然後服務頁面讓用戶等待。更復雜但更具響應性的方法是使用Ajax(例如通過jQuery)定期詢問服務器工作進展的程度。這樣你也可以提供一些進度指標。

+0

這將是一個由管理員/主持人執行的操作,所以它不是那種吝嗇的:) – 2010-09-25 17:53:18

6

是jQuery和一些AJAX會做最正確的。 加載頁面,然後發送〜15個不同的Ajax查詢返回到服務器,讓他們完成異步。這樣,您可以讓Web服務器處理線程(這很好),並專注於在等待時向用戶顯示代碼或虛擬進度條。

+2

只要工作可以按這種方式分解,那麼這是一個非常好的方法...除了避免陷入自己的陷阱線程,在用戶反饋過程中提供反饋會更容易。 – 2010-09-25 17:57:33

+2

這是否是一種好方法取決於您是要合併服務器上還是客戶端上的結果。存在風險,您需要將大量邏輯移動到客戶端,以便在服務器上更好地處理。 – 2010-09-25 19:13:35

+0

這看起來像是一個簡單的修復,但如果您的客戶在不同的標籤中打開了相同的URL,您將很快注意到每個瀏覽器打開連接到單個域的限制。 (很多人現在用websockets發現的東西)與Jim Leonardo提出的相比,你的服務器可以處理的請求數量減少到1/15。 Rohan Singh的答案不那麼複雜,只比Jim的 – Cohen 2013-01-22 13:32:22

7

這似乎是一個非常好的地方在ASP.NET MVC 2中使用新的AsycController。它非常易於使用,並允許您在不阻止請求線程的情況下針對多個獨立源運行查詢。

MSDN has a great example他們在哪裏查詢新聞服務,天氣服務和體育服務。

您可以在它們被查詢每個源依次原來代碼中看到,但在最終版本中,所有的任務並行和控制返回到控制器上運行時,他們都完成了:

public void IndexAsync(string city) 
{ 
    AsyncManager.OutstandingOperations.Increment(3); 

    NewsService newsService = new NewsService(); 
    newsService.GetHeadlinesCompleted += (sender, e) => 
    { 
     AsyncManager.Parameters["headlines"] = e.Value; 
     AsyncManager.OutstandingOperations.Decrement(); 
    }; 
    newsService.GetHeadlinesAsync(); 

    SportsService sportsService = new SportsService(); 
    sportsService.GetScoresCompleted += (sender, e) => 
    { 
     AsyncManager.Parameters["scores"] = e.Value; 
     AsyncManager.OutstandingOperations.Decrement(); 
    }; 
    sportsService.GetScoresAsync(); 

    WeatherService weatherService = new WeatherService(); 
    weatherService.GetForecastCompleted += (sender, e) => 
    { 
     AsyncManager.Parameters["forecast"] = e.Value; 
     AsyncManager.OutstandingOperations.Decrement(); 
    }; 
    weatherService.GetForecastAsync(); 
} 

public ActionResult IndexCompleted(string[] headlines, string[] scores, string[] forecast) 
{ 
    return View("Common", new PortalViewModel { 
     NewsHeadlines = headlines, 
     SportsScores = scores, 
     Weather = forecast 
    }); 
} 
+0

稍微小一點這個鏈接現在被破壞 – PandaWood 2012-10-24 23:53:19

+0

該死的,一個URL應該是一個承諾,特別是在文檔等方面。同樣令人討厭的是,URL只是變化不大(添加「(vs = v.100)」並不明顯)。無論如何,謝謝你指出,@PandaWood。現在修復。 – 2012-10-28 00:17:54

+0

由於MVC 4+控制器包含異步功能,現在這已過時。這裏有一個例子:http://www.asp.net/mvc/overview/performance/using-asynchronous-methods-in-aspnet-mvc-4 – 2015-01-05 15:34:39