Stoppen einer Methode nach einer bestimmten Zeitspanne

8

Ich führe parallele Operationen auf einer Liste von PCs durch, die ich vom ActiveDirectory bekomme. Ich benutzte diese Methode, um PC-Zustände zu prüfen, wie wenn der Computer online war oder wenn ein bestimmtes Verzeichnis existiert. Aufgrund der Art dieser manchmal langsamen Operationen wollte ich jedoch ein Zeitlimit einfügen, damit meine Anwendung fortgesetzt werden konnte.

%Vor%

Dies funktioniert größtenteils, aber die Verarbeitungsnutzung schien etwas anzusteigen, und in einigen Fällen kam es zu Out-of-Memory-Ausnahmen. Also habe ich seit der Änderung der Methode die Verwendung von Aufgaben in der Hoffnung, dass der ThreadPool die oben genannten Probleme beseitigen würde:

%Vor%

Ich habe jedoch das Gefühl, dass ich den ThreadPool gerade mit Prozessen auffülle, die auf diese potenziell langen Aufgaben warten. Da ich die Funktion der Aufgabe als Parameter übergebe, sehe ich keinen Weg, ein Löschungs-Token zu verwenden, jedoch ist meine Erfahrung mit diesen Klassen sehr eingeschränkt und mir fehlen möglicherweise überlegene Techniken.

So habe ich die obige Methode verwendet:

%Vor%

Eine kurze Anmerkung, ich führe nur die obige Prüfung durch, nachdem ich bereits bestätigt habe, dass der PC über einen WMI-Aufruf online ist (auch mit MethodTimeout). Ich bin mir durch meine frühen Tests bewusst, dass das Überprüfen des Verzeichnisses bevor es unglaublich ineffizient ist.

Ich bin natürlich auch bereit, meinen Ansatz mit etwas Besserem zu zerstören. Meine Loyalität liegt in der Anzahl der Operationen pro Sekunde, nicht einfach, was ich mir vorstellen kann.

    
Parrish Husband 31.10.2013, 23:39
quelle

3 Antworten

6

Ich bin vielleicht der Vorbote schlechter Nachrichten hier, aber dieses Szenario ist viel schwieriger zu handhaben, als die meisten Leute denken. Es sieht so aus, als ob Sie dies bereits erkennen. Die Verwendung der kooperativen Auslöschungsmechanismen ist alles in Ordnung, aber Sie müssen in der Lage sein, den zeitaufwendigen Vorgang tatsächlich abzubrechen, um sie effektiv verwenden zu können. Das Problem ist, dass Directory.Exists nicht abgebrochen werden kann.

Das Problem mit Ihrer ersten Lösung besteht darin, dass Sie einen Thread abbrechen. Dies ist keine gute Idee, da es den Thread an unvorhersehbaren Punkten stoppt. Dies kann dazu führen, dass Datenstrukturen für alles, was auf dem Aufruf-Stack ausgeführt wurde, beschädigt wurden, als der Abbruch injiziert wurde. In diesem speziellen Fall wäre ich nicht überrascht, wenn der Thread.Abort -Aufruf wirklich hängen würde. Der Grund dafür ist, dass Abbrüche normalerweise verzögert werden, während die Ausführung in nicht verwaltetem Code erfolgt. Es ist wahrscheinlich, dass Directory.Exists auf ein nicht verwaltetes Modul verweist. Wenn das der Fall ist, wird der Abbruch sowieso nicht funktionieren.

Das Problem mit der zweiten Lösung ist, dass Sie die Aufgabe verwaist lassen. Dieser Directory.Exists -Aufruf würde immer noch irgendwo in einem Thread-Pool-Thread ausgeführt werden. Dies ist, weil Sie es nicht wirklich abgebrochen haben.

Um ehrlich zu sein, bin ich nicht wirklich sicher, was ich dagegen tun soll. Das Fehlen einer abbrechbaren Methode Directory.Exists ist sehr problematisch. Mein erster Gedanke ist, ein Schreiben oder Lesen aus dem Verzeichnis, das Sie testen möchten, als eine Art Proxy zu versuchen, um seine Existenz zu überprüfen. Die Klasse FileStream hat abbrechbare Operationen. Tatsächlich akzeptieren viele Methoden sogar CancellationToken als Parameter. Oder Sie können FileStream schließen und damit alle ausstehenden Operationen abbrechen. Eine andere Option könnte darin bestehen, die Win32-API-Funktionen zum Ausführen der IO zu verwenden. Dann können Sie CancelSynchronousIo bei Bedarf aufrufen.

Ich weiß, dass das keine große Antwort ist, denn alles, was ich wirklich getan habe, ist, Ihnen zu sagen, was Sie nicht tun können, aber ich habe keine endgültige Lösung angeboten. Der Punkt ist, dass die beste Lösung mit einer abbrechbaren Operation beginnt. Es ist bedauerlich, dass einige der BCL-Klassen diese nicht bereitstellen, selbst wenn sie es sollten.

    
Brian Gideon 01.11.2013, 02:50
quelle
4

Wenn Sie .Net 4.5 verwenden, können Sie % co_de verwenden % :

%Vor%     
Damian Drygiel 31.10.2013 23:50
quelle
0

Könnte so etwas funktionieren? Sie müssten verlangen, dass der Verbraucher Ihnen eine Func übergibt, die eine CancellationTokenSource übernimmt. Das Func wäre dafür verantwortlich, IsCancellationRequested an der entsprechenden Stelle in seinem Code zu überprüfen ...

%Vor%

Mein Wissen über TPL ist nicht besonders gut, also tut mir leid, wenn mein Code nicht ganz stimmt. Habe keine Möglichkeit, es mit meiner älteren Version von VS zu testen. Korrigiert / editiert welcome:)

    
Jeff Bridgman 01.11.2013 00:11
quelle