2017-11-13 3 views
-2

Ich habe eine Konsolen-App, die ein paar Aufgaben parallel ausführt. In meinem Fall ist der wichtige Teil, dass ich möchte, dass die Aufgaben gleichzeitig abgeschlossen werden. Ich weiß, wie lange jede Aufgabe dauern wird. Die Idee ist also, jede Aufgabe in der Parallel.ForEach mit individueller Zeitverzögerung pro Aufgabe zu verzögern, so dass alle zur gleichen Zeit fertig sind und am Ende alle Aufgaben ungefähr zur selben Zeit abgeschlossen werden wie die, die am meisten Zeit benötigt.Parallele Aufgabenausführung zu unterschiedlichen Zeiten

Beispiel:

interface IService 
{ 
    void DoWork(); 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var services = new List<IService>(); 
     services.Add(new ServiceA());//Takes 500ms to DoWork() 
     services.Add(new ServiceB());//Takes 1000ms to DoWork() 
     services.Add(new ServiceC());//Takes 5000ms to DoWork() 

     Parallel.ForEach(services, z => 
     { 
      Stopwatch sw = new Stopwatch(); 
      sw.Start(); 
      z.DoWork(); 
      Console.WriteLine($"Ready for {sw.Elapsed}"); 
     }); 
    } 
} 

Ausgang:

Ready for 00:00:00.5006837 
Ready for 00:00:01.0002284 
Ready for 00:00:05.0010202 
Press any key to continue . . . 

Wie Sie den Code modifizieren, um die Ausgabe so aussehen:

Ready for 00:00:05.5006837 
Ready for 00:00:05.0002284 
Ready for 00:00:05.0010202 
Press any key to continue . . . 

ich denke, die naheliegendste Lösung wäre, Unterscheiden Sie, welcher Dienst z in der Schleife ist und fügen Sie vor dem Aufruf von z.DoWork() benutzerdefinierte Thread.Sleep hinzu, aber ich schaue g für eine intelligentere Lösung.

+0

Sie können nicht einfach garantieren, dass alle Aufgaben gleichzeitig ausgeführt werden. Sie können jedoch warten, bis alle fertig sind, bevor Sie fortfahren. Sehen Sie sich die Task.WaitAll() -Dokumentation an. – legrojan

+0

Verwenden Sie nicht mehrere verschiedene Parallelisierungsparadigmen gleichzeitig. * Benutze entweder Aufgaben, * oder * verwende die 'Parallel' Klasse. Benutze nicht beides. Sie sollten auch nicht den 'Task'-Konstruktor verwenden. Wenn Sie eine "Task" erstellen möchten, die eine Funktion in einem Thread-Pool-Thread ausführt, verwenden Sie stattdessen "Task.Run", um bereits gestartete Aufgaben zu erstellen. – Servy

+0

Ich möchte nicht, dass sie zur gleichen Zeit aber ungefähr gleichzeitig mit einer Differenz von einigen Millisekunden abgeschlossen werden – IIvanov

Antwort

1

Danke für die Hilfe! Das wollte ich erreichen. Alle Dienste beenden ihre Arbeit zur gleichen Zeit. Ist das der richtige Weg?

class Program 
{ 
    static void Main(string[] args) 
    { 
     ServiceA a = new ServiceA(); 
     ServiceB b = new ServiceB(); 
     ServiceC c = new ServiceC(); 

     int maxDelay = 3000; 
     var sw = new Stopwatch(); 
     sw.Start(); 

     Task taskA = Task.Delay(maxDelay - a.ResponseTime).ContinueWith(x => 
      { 
       a.DoWork(); 
       Console.WriteLine($"taskA ready for {sw.Elapsed}"); 
      }); 

     Task taskB = Task.Delay(maxDelay - b.ResponseTime).ContinueWith(x => 
      { 
       b.DoWork(); 
       Console.WriteLine($"taskB ready for {sw.Elapsed}"); 
      }); 

     Task taskC = Task.Delay(maxDelay - c.ResponseTime).ContinueWith(x => 
     { 
      c.DoWork(); 
      Console.WriteLine($"taskC ready for {sw.Elapsed}"); 
     }); 

     taskA.Wait(); 
     taskB.Wait(); 
     taskC.Wait(); 

     Console.WriteLine(sw.Elapsed); 
    } 
} 

class ServiceA 
{ 
    public int ResponseTime { get => 500; } 
    public void DoWork() => Thread.Sleep(500); 
} 

class ServiceB 
{ 
    public int ResponseTime { get => 1000; } 
    public void DoWork() => Thread.Sleep(1000); 
} 

class ServiceC 
{ 
    public int ResponseTime { get => 3000; } 
    public void DoWork() => Thread.Sleep(3000); 
} 

Ausgang:

taskA ready for 00:00:03.0084344 
taskC ready for 00:00:03.0102184 
taskB ready for 00:00:03.0102588 

* Thread.Sleep (x) stellt einige zeitraubende Operationen.

Verwandte Themen