2017-10-10 152 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感谢您指出 –