2017-10-10 4 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가 원하는 것은 OP가 추가 된 작업을 순차적으로 완료하기를 원하는 점에서 ThreadPool과 다릅니다. ThreadPool에는 그러한 보장이 없다. 사실 ThreadPool의 아이디어는 다중 스레드를 사용하여 병렬로 작업하는 것이다 (편집 : 물론 스레드를 다시 사용한다). 이제는 이러한 작업을 동기식으로 실행하거나 대기를 위해 스레드를 사용하는 다른 방법을 통해 달성 할 수 있습니다 ... OP는 그 중 하나도 원하지 않습니다. – Theraot

+0

Task 클래스는 매우 잘 조합되어 있으며, 메인 태스크를 시퀀싱하기 위해 ContinueWith와 서브 태스크 완료를 기다리는 WaitAll 만 있으면된다. 쉬운 peasy,하지만 그것은 당신이 자신의 threadpool을 만들 때 볼 수 없게됩니다. –

답변

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); 

작업에 작업이 없기 때문에 작업에 비동기 작업이 포함될 수 있으므로 Run 메서드는 작업을 기다리지 않으므로 Task.Run(Action action)을 실행하고 있습니다. Task.Run(Func<Task> task)Run 메서드를 호출하면 해당 메서드가 작업임을 알게되고

+0

@Theraot 지적 해 주셔서 감사합니다. –

관련 문제