2016-09-20 86 views
-1

我有一個基類JobBase,它有一個方法Execute()它返回一個任務。有幾個類從JobBase繼承,並執行一些異步操作。我需要將繼承類的實例放入列表中並順序執行它們,因此在作業1完成時啓動job1,job2,job3等job2,在作業2完成時啓動作業3等。順序處理任務

所以隊列可能包含任意數量的作業。 例如:job1下載一些內容,job2讀取內容。在一個另一種情況下,JOB1下載一些內容,JOB2下載一些其他內容,作業3讀取內容等

// The base class 
public abstract class JobBase 
{ 
    public abstract Task Execute(); 
} 

// inherited jobs 
public class Job1 : JobBase 
{ 
    public override Task Execute() 
    { 
     // this one: return Task.Run() 
     // or this one?: 
     Task task = new Task(async() => 
     { 
      await Task.Delay(2000); 
     }); 
     return task; 
    } 
} 

public class Job2 : JobBase 
{ 
    public override Task Execute() 
    { 
     Task task = new Task(async() => 
     { 
      await Task.Delay(1000); 
     }); 
     return task; 
    } 
} 

主程序:

private static void Main(string[] args) 
{ 
    var jobs = new List<JobBase>(); 
    jobs.Add(new Job1()); 
    jobs.Add(new Job2()); 

    List<Task> tasks = new List<Task>(); 
    for (int i = 0; i < jobs.Count; i++) 
    { 
     var jobNr = i; 
     Task task = jobs[jobNr].Execute(); 
     tasks.Add(task); 

     task.Start(); 
    } 

    Console.WriteLine("Starting WaitAll"); 
    Task.WaitAll(tasks.ToArray()); 

    Console.WriteLine("Finished"); 
    Console.ReadKey(); 
} 

實際上,任務被執行,我無法控制它們執行(或完成)的順序。另外,如果前一個成功,我想獲得每項工作的結果(bool)並繼續下一個工作。

我閱讀並嘗試了SequentialTask​​Scheduler,解決方案與TaskCompletionSource,關於Processing tasks as they complete的教程。 由於作業(任務)的數量未知,我無法使用ContinueWith。

請看下面的例子及其輸出。爲簡單起見有Job一個類從JobBase這需要索引和延遲值繼承:

public class Job : JobBase 
{ 
    private readonly int _index; 
    private readonly int _delay; 

    public Job(int index, int delay) 
    { 
     _index = index; 
     _delay = delay; 
    } 

    public override Task Execute() 
    { 
     Task task = new Task(async() => 
     { 
      Console.WriteLine("Job {0} before delay", _index); 
      await Task.Delay(_delay); 
      Console.WriteLine("Job {0} after delay", _index); 
     }); 
     return task; 
    } 
} 

添加某些情況下到任務列表,如

jobs.Add(new Job(1, 3000)); 
jobs.Add(new Job(2, 2000)); 
jobs.Add(new Job(3, 1000)); 

我得到以下結果:

Starting WaitAll 
Job 2 before delay 
Job 3 before delay 
Job 1 before delay 
Finished 
Job 3 after delay 
Job 2 after delay 
Job 1 after delay 

(JOB3完成在第一,由於延遲小於JOB2等)

期望的結果是:

Starting WaitAll 
Job 1 before delay 
Job 1 after delay 
Job 2 before delay 
Job 2 after delay 
Job 3 before delay 
Job 3 after delay 
Finished 

什麼是按順序運行的異步任務的最佳方法呢?我可以自由地更改Execute方法的簽名,例如返回Task或任何其他內容。

+0

請認識到,如果你看看所需的結果,總運行時間將在5秒左右(3 + 2 + 1)。平行運行時大約需要3秒。 –

回答

0

試試這個:

async void Main(string[] args) 
{ 
    var jobs = new List<JobBase>(); 
    jobs.Add(new Job(1, 3000)); 
    jobs.Add(new Job(2, 2000)); 
    jobs.Add(new Job(3, 1000)); 

    for (int i = 0; i < jobs.Count; i++) 
    { 
     var t = jobs[i].Execute(); 
     await t; 
    } 

    Console.WriteLine("Finished"); 
    Console.ReadLine(); 
} 

請注意,我們不再使用

Task.WaitAll(tasks.ToArray()); 

,因爲它允許任務並行運行。我們只是在循環中等待他們。

修改作業類這樣的:

public class Job : JobBase 
{ 
    private readonly int _index; 
    private readonly int _delay; 

    public Job(int index, int delay) 
    { 
     _index = index; 
     _delay = delay; 
    } 

    public override Task Execute() 
    { 
     Task task = Task.Run(async() => 
     { 
      Console.WriteLine("Job {0} before delay", _index); 
      await Task.Delay(_delay); 
      Console.WriteLine("Job {0} after delay", _index); 
     }); 
     return task; 
    } 
} 

Task task = new Task(async() => 

Task task = Task.Run(async() => 
0

所以,這個隊伍的變化...

什麼隊列?你當前的代碼使用List<T>Task.WaitAll,如果你知道你有多少任務在等待,那麼這很好。它不能用作「任務跑步者」,因爲不可能中斷WaitAll並說「哦,你現在有一項新任務」。

這聽起來像你對我要尋找的是ActionBlock<T>

private static void Main(string[] args) 
{ 
    var jobs = new ActionBlock<JobBase>(x => x.Execute()); 
    jobs.Add(new Job1()); 
    jobs.Add(new Job2()); 
    jobs.Complete(); 

    Console.WriteLine("Starting Wait"); 
    Task.WaitAll(jobs.Completion.Wait()); // only using Wait because this code is in Main 

    Console.WriteLine("Finished"); 
    Console.ReadKey(); 
} 

ActionBlock<T>默認情況下將同時執行一個任務。

此外,我想得到每個工作的結果(布爾),並繼續下一個工作,如果前一個工作成功。

如果您報告有例外的錯誤,則ActionBlock將停止處理第一個失敗的作業。

+0

你是對的,這是一個隊列,在這個例子中它是一個列表。我不知道Dataflow庫,所以ActionBlock就是我正在尋找的。謝謝。 – user819068