2017-10-10 155 views
1

我正在嘗試構建一種可以按順序運行若干任務的調度程序(這可能不是相關術語)。C#6正在等待完成任務和所有子任務

這裏是我的POC代碼(請忽略隊列/出列機制較差,但不是這裏的問題,我猜)

編輯:感謝的@Theraot

static void Main(string[] args) 
    { 
     ProcessingQueue o_q = new ProcessingQueue(); 
     o_q.Enqueue(async() => { await SimulateTaskSequence(1); }); 
     o_q.Enqueue(async() => { await SimulateTaskSequence(2); }); 

     Console.ReadLine(); 
    } 

    public static async Task SimulateTaskSequence(int taskNbr) 
    { 
     Console.WriteLine("T{0} - Working 1sec", taskNbr); 
     Thread.Sleep(1000); 

     Console.WriteLine("T{0} - Zzz 1st 1sec", taskNbr); 
     await Task.Delay(1000); 

     Console.WriteLine("T{0} - Working 1sec", taskNbr); 
     Thread.Sleep(1000); 

     Console.WriteLine("T{0} - Done", taskNbr); 
    } 

    public class ProcessingQueue 
    { 
     Queue<Action> _Queue = new Queue<Action>(); 
     private bool _stillRunning = false; 

     public void Enqueue(Action a) 
     { 
      lock (_Queue) 
      { 
       _Queue.Enqueue(a); 

       if (_stillRunning == false) 
       { 
        StartProcessing(); 
       } 
      } 
     } 


     private void StartProcessing() 
     { 
      _stillRunning = true; 

      Task.Run(async() => 
      { 
       Action a = null; 

       while (true) 
       { 
        lock (_Queue) 
        { 
         if (_Queue.Any() == true) 
         { 
          a = _Queue.Dequeue(); 
         } 
         else 
         { 
          break; 
         } 
        } 

        await Task.Run(a); //how to wait for all subtasks!!??? 
       } 
       _stillRunning = false; 
      }); 
     } 

我的問題的幫助一旦第一個任務(T1)的第一個等待發生,第二個任務(T2)開始執行。

我得到以下輸出:

T1 - Working 1sec 
T1 - Zzz 1st 1sec 
T2 - Working 1sec 
T2 - Zzz 1st 1sec 
T1 - Working 1sec 
T1 - Done 
T2 - Working 1sec 
T2 - Done 

但是我期待是:

T1 - Working 1sec 
T1 - Zzz 1st 1sec 
T1 - Working 1sec 
T1 - Done 
T2 - Working 1sec 
T2 - Zzz 1st 1sec 
T2 - Working 1sec 
T2 - Done 

我明白爲什麼這是默認的行爲,但我需要改變。我在一個新的TaskFactory中玩耍TaskContinuationOptions和TaskCreationOptions,但沒有更好的結果。 這甚至可能嗎?

非常感謝 克里斯托夫

+0

您的ProcessingQueue類已經存在於框架中,它是ThreadPool。很難正確替換,並且它不會執行ThreadPool不做的任何操作。除了等待和即時出錯。不要這樣做。 –

+0

@HansPassant OP所需要的與ThreadPool不同,OP需要添加的任務按順序完成。在ThreadPool中,你沒有這樣的保證,實際上ThreadPool的想法是使用多個線程並行運行(編輯:並重用線程)。現在,可以通過同步運行這些任務來實現,或者通過使用Thread來等待的其他方式來實現... OP不需要任何這些任務。 – Theraot

+0

Task類組合得非常好,他所需要的只是ContinueWith對主任務和WaitAll進行排序,以等待子任務完成。簡單易用,但是當你發明自己的線程池時很難看清楚。 –

回答

2

我建議建立,而不是ProcessingQueue<Func<Task>>ProcessingQueue<Action>

public class ProcessingQueue 
{ 
    Queue<Func<Task>> _Queue = new Queue<Func<Task>>(); 

    private bool _stillRunning = false; 

    public void Enqueue(Func<Task> a) 
    { 
     lock (_Queue) 
     { 
      _Queue.Enqueue(a); 

      if (_stillRunning == false) 
      { 
       StartProcessing(); 
      } 
     } 
    } 

    private void StartProcessing() 
    { 
     _stillRunning = true; 

     Task.Run(async() => 
     { 
      Func<Task> a = null; 

      while (true) 
      { 
       lock (_Queue) 
       { 
        if (_Queue.Any() == true) 
        { 
         a = _Queue.Dequeue(); 
        } 
        else 
        { 
         break; 
        } 
       } 

       await a(); //how to wait for all subtasks!!??? 
      } 
      _stillRunning = false; 
     }); 
    } 

說明

在編寫代碼有問題,

Action a; 
... 
await Task.Run(a); 

您正在執行Task.Run(Action action),因爲操作可能包含異步任務,所以Run方法不會在任務上等待,因爲沒有任務。當你調用Task.Run(Func<Task> task)Run方法知道它是任務,它將等待它,

+0

@Theraot感謝您指出 –