2013-12-19 65 views
5

我必須處理大約200.000個對象(在桌面應用程序中),每個對象需要大約20毫秒才能處理。爲了加速這一點,我想同時做到這一點。使用任務並行庫進行計劃

對於測試,我只是把每個對象放在一個單獨的任務中,但由於工作量小,這隻會產生微小的速度提升。所以我的第一個問題是:

是否有一個巧妙的(但不是太複雜)的方式來找到這些對象的最佳批量大小?我想我可以進行一些本地測試,看它是否最快將它們分成10,20或100個對象進行分組,但這看起來有點不理想。其次(也是更重要的):大多數對象只要有一些CPU時間就應該被處理。但是,用戶將始終查看10-20個對象。我希望始終能夠將用戶正在查看的對象置於隊列的前端,以便提供流暢的用戶體驗。用戶可能會一直導航,所以我認爲始終能夠快速重新安排訂單非常重要。 (20 ms * 20應該能夠在大約0.4秒內處理)。

有人可以幫助我一個良好的設計模式來處理這些對象嗎?

+0

你說的是什麼樣的處理?它是否受CPU限制? – svick

+0

您可能需要定義_optimal_ wrt批量大小。最簡單的方法是:按核心/處理器數量劃分項目數量。總吞吐量是一個明顯的因素,但對用戶的響應也很重要;如果批量大小太大,那麼如果用戶想要查看恰好處於批次中的項目,則相關線程可能需要很長時間才能交付這些項目(除非線索將處理的項目遞送到較小的組中)。您的線程可以支持重新計劃,以便在必要時項目X..Y必須移至隊列頭部。 – groverboy

+0

'隊列'是顯而易見的集合類,但它不支持重新計劃(除非使用像「SkipWhile」這樣的擴展方法)。或者,使用具有方法「AddRange」,「RemoveRange」的'List '。 – groverboy

回答

3

如果對象位於集合中,則可以使用Parallel.ForEach或Parallel.For。由於您的用戶響應性要求,Parallel.For將是更好的選擇。

不幸的是,測量性能和根據結果調整策略是不可替代的。

+0

你能解釋一下爲什麼你認爲Parallel.For會更好? – svick

+0

OP的要求是用戶正在查看的任何對象都優先處理。假設用戶正在查看容器中的連續項目,可以在該項目上運行Parallel.For。 – StevieB

1

如果您想要並行處理項目並且不關心訂單,只需使用Parallel.ForEach()(從後臺線程中調用它以便不阻止UI線程)。

但是,如果您想要實現動態優先級更改,情況會更加複雜。

一種方法是讓一個對象,我們稱之爲Job,這將代表必須執行的單個動作。然後你會有一個處理作業隊列的方法,但是如果有的話執行那些具有高優先級的方法。喜歡的東西:

Queue<Job> jobs; 
IEnumerable<Job> priorityJobs; 

void ProcessJobs() 
{ 
    while (true) 
    { 
     Job job = null; 

     lock (jobs) 
     { 
      job = priorityJobs.FirstOrDefault(j => j.NotYetStarted); 

      if (job == null) 
      { 
       do 
       { 
        if (jobs.Count == 0) 
         return; 

        job = jobs.Dequeue(); 
       } while (job.NotYetStarted); 
      } 

      job.NotYetStarted = false; 
     } 

     job.Execute(); 
    } 
} 

這樣,你會啓動線程並行執行ProcessJobs(),例如:

var tasks = Enumerable.Range(0, Environment.ProcessorCount) 
    .Select(_ => Task.Run(() => ProcessJobs()));