2015-07-29 3 views
9

Ich führe eine Task erneut, wenn es abgeschlossen ist. Unten ist die Funktion, die ich in der Application_Start meiner Anwendung aufrufen.Wie führen Sie mehrere Aufgaben in C# aus und erhalten ein Ereignis nach Abschluss dieser Aufgaben?

private void Run() 
{ 
    Task t = new Task(() => new XyzServices().ProcessXyz()); 
    t.Start(); 
    t.ContinueWith((x) => 
    { 
     Thread.Sleep(ConfigReader.CronReRunTimeInSeconds); 
     Run(); 
    }); 
} 

Ich möchte mehrere Aufgaben ausführen, Nummer, die von web.config App Settings gelesen werden.

ich so etwas wie dies versuchen,

private void Run() 
{ 
    List<Task> tasks = new List<Task>(); 
    for (int i = 0; i < ConfigReader.ThreadCount - 1; i++) 
    { 
     tasks.Add(Task.Run(() => new XyzServices().ProcessXyz())); 
    } 

    Task.WhenAll(tasks); 

    Run(); 
} 

Was ist der richtige Weg, dies zu tun?

+0

, wenn Sie in den Aufbau Ihrer eigenen Taskrunner graben wollen nicht/diese Klasse erstreckt ich wahrscheinlich für die erste Aufgabe durch den Einsatz bis zum Ende warten würden 'tasks.First(). Wait();' und dann eine while-Schleife mit einem Thread.Sleep, um den Status der verbleibenden Aufgaben zu beobachten. –

+1

Sie möchten ein Stück Code in vorgegebenen Zeitintervallen wiederholt ausführen? Klingt nach dem genauen Grund, warum 'Timer' wirklich existiert. Und natürlich, wenn Sie dabei bleiben wollen, binden Sie einfach Ihre Fortsetzung an das Ergebnis von "Task.WhenAll" und alles wird genauso wie zuvor funktionieren. – Luaan

+0

Sie benötigen entweder 'aware Task.WhenAll (tasks);' oder 'Task.WaitAll (tasks);'. Der eine ist ein asynchroner Aufruf und sollte erwartet werden, der andere ist eine normale Funktion, die in einem synchronen Kontext aufgerufen werden kann. Natürlich können Sie auch für die hässliche 'Task.WhenAll (Aufgaben) .Wait();' – Dorus

Antwort

1

Wenn Sie alle Aufgaben warten möchten zu beenden und starten Sie sie, Marks Antwort richtig ist.

Aber wenn Sie wollen Thread Aufgaben jederzeit ausgeführt werden (sobald eine neue Aufgabe beginnen, wie jeder von ihnen endet), dann

void Run() 
{ 
    SemaphoreSlim sem = new SemaphoreSlim(ConfigReader.ThreadCount); 

    Task.Run(() => 
    { 
     while (true) 
     { 
      sem.Wait(); 
      Task.Run(() => { /*Your work*/ }) 
       .ContinueWith((t) => { sem.Release(); }); 
     } 
    }); 
} 
+0

Warum die innere 'Task.Run'? Du nimmst einen Thread auf, der blockiert, während ein anderer benutzt wird, um etwas synchron auszuführen. Verwende einfach 'sem.Wait(); versuch {RunWhatever(); } endlich {sem.Release(); } '. – Luaan

+0

@Luaan Nein Es ist nicht das, was ich mit meinem Code machen möchte. Ich warte nicht darauf, dass eine Aufgabe beendet wird, sondern starte eine neue Aufgabe. Ich erstelle nur eine neue Aufgabe, wenn einer von ihnen beendet wird. Es werden also immer * ThreadCount * Aufgaben ausgeführt. – EZI

+0

Keine Aufgaben.WhenAll verwendet den ThreadPool, der automatisch die "beste" Anzahl von Aufgaben auf einmal ausführt, während die anderen anstehen? –

8

, wenn Sie die Aufgaben, die man ausführen möchten nach die andere,

await Task.Run(() => new XyzServices().ProcessXyz()); 
await Task.Delay(ConfigReader.CronReRunTimeInSeconds * 1000); 

wenn Sie wollen, gleichzeitig ausgeführt werden, wie die Task-Scheduler erlaubt,

await Task.WhenAll(new[] 
    { 
     Task.Run(() => new XyzServices().ProcessXyz()), 
     Task.Run(() => new XyzServices().ProcessXyz()) 
    }); 

So sollte Ihre Methode so etwas wie,

private async Task Run() 
{ 
    var tasks = 
     Enumerable.Range(0, ConfigReader.ThreadCount) 
     .Select(i => Task.Run(() => new XyzServices().ProcessXyz())); 

    await Task.WhenAll(tasks); 
} 
+0

Ich lese früher, dass warten auf die Aufgaben ist nicht, was ihre Ausführung beginnt, dass sie tatsächlich sofort oder in der Umgebung beginnen. Ist das richtig? Es würde Ihre ersten Aussagen verkomplizieren. –

+0

@BenKnoble, es ist ein guter Punkt, habe ich geklärt. – Jodrell

+0

Wenn die Funktionen, die Sie aufrufen, selbst asynchron sind, müssen Sie sie nicht in eine "Task.Run" umbrechen. Es ist jedoch wichtig zu wissen, dass eine asynchrone Task sofort auf dem aktuellen Thread gestartet wird und nur dann den Kontext wechselt, wenn sie selbst in einen asynchronen Aufruf läuft. Für CPU-schwere Funktionen sollten Sie sie sicher in eine "Task.Run" einbinden. Für Funktionen, die schnell zu einem asynchronen Aufruf (normalerweise IO) wechseln, erhalten Sie eine bessere Leistung, indem Sie sie nicht umhüllen. – Dorus