2017-12-28 20 views
-1

Mein Ziel ist es, mehrere Verknüpfungen gleichzeitig zu laden und für jede eine Aufgabe zu erstellen.C# Mehrere Tasks ausführen, die die Website analysieren und zurückgeben, wenn alle fertig sind

Die Task ruft eine asynchrone Methode auf, die die Links analysiert und Sublinks zurückgibt, die im Gegenzug geparst werden (mit WebBrowser) und dann einen Downloadlink zurückgeben.

Die erste asynchrone Methode ruft 2 nachfolgende Methoden für diese Arbeit auf.

Mein Problem ist Task.Factory.ContinueWhenAll würde nur zurück, wenn die erste Methode beendet, und wird nicht auf den Rest der Arbeit warten. Ich möchte nur fortfahren, wenn ich alle Download-Links bereit habe, die möglicherweise mehrere Webseiten-Parsing benötigen, bevor sie es sind.

Derzeit mein Code ist folgende:

var tasks = new List<Task>(); 
for (var index = 0; index < items_checklist.CheckedItems.Count; index++) 
{ 
    var item = items_checklist.CheckedItems[index]; 
    Task task = Task.Factory.StartNew(
        () => GetMirrors(((Item) item).Value, ((Item) item).Text) 
        , CancellationToken.None 
        , TaskCreationOptions.None 
        , TaskScheduler.FromCurrentSynchronizationContext() 
    ); 
    tasks.Add(task); 
} 

Task.Factory.ContinueWhenAll(tasks.ToArray(), GetLinks_Finished => 
{ 
    SetLinksButtonText(@"Links Ready"); 
    SetLinksButtonState(false); 
    SetDownloadButtonState(true); 
    Cursor.Current = DefaultCursor; 
}); 

Diese zurückkehren wird, wenn alle GetMirrors beenden, aber GetMirrors nennen würde „tempbrowser_DocumentCompleted“ (WebBrowser complete-Ereignis), die wiederum nennen würde „LoadLinkIntoQueue“, um den Download-Link zu laden in die Warteschlange.

Ich möchte ContinueWhenAll fortsetzen, wenn alle LoadLinkIntoQueue ausgeführt werden.

Was fehlt mir an Logik?

+0

Ich weiß nicht, ob es dafür Unterstützung gibt. Wenn nicht, müssen Sie einen Zähler für die Anzahl der laufenden Threads erstellen. Fügen Sie allen abschließenden Aufgaben eine Fortsetzung hinzu, die den Zähler nur dekrementiert. Und feuert die letzte Logik, die es nach der finalen letzten Aufgabe haben sollte. – Christopher

+1

Dies klingt wie ein Job für [Dataflow] (https://blog.stephencleary.com/2012/09/introduction-to-dataflow-part-1.html) oder [RX.Net] (http: // reactivex. io/intro.html) – JSteward

+1

Sie können dies ohne Datenfluss oder rx.net tun. Veröffentlichen Sie den Code für die GetMirrors-Methode. – Sievajet

Antwort

2

Sie können eine TaskCompletionSource in Ihrer GetMirrors Methode erstellen, die die Methode ist, die in dem Task.Factory.StartNew Aufruf innerhalb Ihrer for-Schleife von URLs verwendet wird, um zu verarbeiten.

In GetMirrors würden Sie das DocumentCompleted-Ereignis eines neuen WebBrowsers anschließen, der die SetResult auf der TaskCompletionSource aufrufen wird, wodurch die Aufgabe zu Übergang zu Abgeschlossen wird.

Ihre Umsetzung würde so aussehen:

Task<string> GetMirrors(string url, string somethingelse) 
{ 

    // this will signal that the Task is completed 
    // we want the parent to wait 
    var tcs = new TaskCompletionSource<string>(TaskCreationOptions.AttachedToParent); 

    // give each task their own WebBrowser instance 
    WebBrowser tempbrowser = new WebBrowser(); 
    tempbrowser.ScriptErrorsSuppressed = true; 
    this.Controls.Add(tempbrowser); 

    tempbrowser.DocumentCompleted += (s, e) => { 
     // LoadLinkIntoQueue call 
     // we have a result so signal to the CompletionSource that we're done 
     tcs.SetResult(e.Url.ToString()); 

     this.Controls.Remove(tempbrowser); 
    }; 

    // hook up errorhandling if you need that, left as an exercise. 

    tempbrowser.Navigate(url); 
    // we return the Task from the completion source 
    return tcs.Task ; 
} 

Sie auch SetException auf der TaskCompletionSource Instanz aufrufen können, wenn Sie Ausnahmen zurückgeben möchten, die auftreten.

Beachten Sie, dass ich in diesem Code einen WebBrowser für jede Aufgabe instanziiere, so dass Sie sich keine Gedanken über die Serialisierung der Aufgaben machen müssen, damit nur ein einziges WebBrowser-Steuerelement eine Aufgabe behandelt.

+0

Dies funktioniert nur mit einer einzigen URL. – Sievajet

+1

@Sievajet Ja, das ist meine Vermutung bei der Implementierung der Methode, die in der Schleife sitzt, die das OP zeigt, die alle Aufgaben erstellt. Ich wollte das alles nicht noch einmal hinzufügen. Aber du hast recht, dieser Code funktioniert nicht für mehrere URLs, er funktioniert im Kontext mit dem Code des OP mit mehreren URLs, zumindest in meinem Test. – rene

+0

Erste Implementierung und Tests zeigen, dass dies funktioniert und fast wie vorgesehen. Ich muss mehr Tests machen, mit Debug-Ausgabe, wenn es funktioniert, werde ich meine Antwort aktualisieren und es zur akzeptierten Antwort machen, danke. –

Verwandte Themen