2013-03-03 38 views
0

假設我們有一些方法可以做一些大的工作。用回調排隊幾個任務

最初我們不知道有多少種方法(可以是1,可以是10)。

在這段代碼看起來是這樣的:實現此接口的

public interface IWorker 
{ 
    void DoWork(DataContainer data); 
} 

而且幾類。 然後我們有實例列表。

List<IWorker> workers = new List<IWorker>(); 

我想異步運行這些方法。另外,我想在執行所有的回調時進行一些回調。

public void Callback() 
{ 
    Console.WriteLine("everything done"); 
} 

有沒有辦法做到這一點,而無需編寫自定義包裝或其他?使用ThreadPool,任務,並行?

據我所知平行塊線程直到任務完成,所以這不是prefferd行爲。

當創建任務時,應該有沒有參數的方法,因爲我已經看到,所以這也不好。

在ThreadPool中有可能使用方法QueueUserWorkItem,但使用這種方法我不會得到一個「完全完成」回調。

當然,我可以製作自己的包裝器,它將使用ThreadPool實現所需的功能,但目標是在不寫這樣的包裝器的情況下做到這一點。

任何人都可以幫忙嗎? 謝謝。

回答

3

您正在尋找TPL和Task類。

爲每個操作Task,然後調用Task.WhenAll得到一個總任務

+0

是的,這聽起來不錯,但其構造函數中的任務等待一個沒有輸入參數的方法。我的方法有這樣一個。 – steavy 2013-03-03 20:10:52

+1

@steavy沒有必要爲任務提供輸入參數,因爲您不需要在任務創建後安排任務,在其他工作中,任務調度程序不需要任何東西給委託。相反,只需使用lambda關閉任何可能需要的變量作爲函數的參數,而不是直接傳遞值。 – Servy 2013-03-03 20:15:08

+0

謝謝。既然你是第一個建議Task.WhenAll標記爲正確答案:) – steavy 2013-03-03 20:28:26

0

聽起來像一個總理候選人的CountdownEvent類:

List<IWorker> workers = new List<IWorker>(); 
using (CountdownEvent e = new CountdownEvent(workers.Count)) 
{ 
    foreach (IWorker worker in workers) 
    { 
     // Dynamically increment signal count. 
     e.AddCount(); 
     // run work itself on another thread 
     ThreadPool.QueueUserWorkItem(delegate(object state) 
     { 
      try 
      { 
       ((IWorker)state[0]).DoWork((DataContainer)state[1]); 
      } 
      finally 
      { 
       e.Signal(); 
      } 
     }, 
     // pass required parameters for block of work 
     new object[] { worker, dataForWorker }); 
    } 

    // wait for all workers to finish 
    e.Wait(); 
    // run callback code 
} 
2

您正在尋找Task.WhenAll。創建一堆任務,完成你想要的任務,然後等待所有任務並繼續回調。我分離出DoWork方法的異步版本 - 如果您總是要異步調用它,則不一定需要這樣做。

public interface IWorker 
{ 
    Task DoWorkAsync(string data); 
    void DoWork(string data); 
} 

public class Worker : IWorker 
{ 
    public Task DoWorkAsync(string data) 
    { 
     return Task.Run(() => DoWork(data)); 
    } 

    public void DoWork(string data) 
    { 
     Console.WriteLine(data); 
     Thread.Sleep(100); 
    } 
} 

public class Runner 
{ 
    public void Callback() 
    { 
     Console.WriteLine("Everything done"); 
    } 

    public void Run() 
    { 
     var workers = new List<IWorker> {new Worker(), new Worker(), new Worker()}; 
     var tasks = workers.Select(t => t.DoWorkAsync("some data")); 

     Task.WhenAll(tasks).ContinueWith(task => Callback()); 

     Console.WriteLine("Waiting"); 
    } 
}