Gibt es, wie der Titel schon sagt, ein Äquivalent zu Process.Start
(ermöglicht das Ausführen einer anderen Anwendung oder Batchdatei), auf das ich warten kann?
Ich spiele mit einer kleinen Konsolen-App und dies schien der perfekte Ort zu sein, um Async zu verwenden und zu warten, aber ich kann keine Dokumentation für dieses Szenario finden.
Was ich denke, ist etwas in diese Richtung:
void async RunCommand()
{
var result = await Process.RunAsync("command to run");
}
c#
async-await
c#-5.0
Linkerro
quelle
quelle
Process.Start
ist asynchron und das OP scheint eine synchrone Version zu wollen.Antworten:
Process.Start()
Startet nur den Prozess, wartet nicht, bis er abgeschlossen ist, daher macht es wenig Sinn, ihn zu erstellenasync
. Wenn Sie es trotzdem tun möchten, können Sie so etwas tunawait Task.Run(() => Process.Start(fileName))
.Wenn Sie jedoch asynchron auf den Abschluss des Prozesses warten möchten, können Sie das
Exited
Ereignis zusammen mitTaskCompletionSource
folgenden Elementen verwenden :quelle
process
undprocess.StartInfo
ändern, was passiert, wenn Sie es ausführen.Start()
. Wenn Sie beispielsweise anrufen,.EnableRaisingEvents = true
bevor Sie die hier gezeigtenStartInfo
Eigenschaften festlegen, funktionieren die Dinge wie erwartet. Wenn Sie es später einstellen, um es beispielsweise zusammenzuhalten.Exited
, obwohl es zuvor aufgerufen wurde.Start()
, funktioniert es nicht richtig -.Exited
wird sofort ausgelöst, anstatt darauf zu warten, dass der Prozess tatsächlich beendet wird. Ich weiß nicht warum, nur ein Wort der Vorsicht.process.SynchronizingObject
sollte die Formularkomponente festgelegt werden, um zu vermeiden, dass Methoden, die Ereignisse verarbeiten (z. B. Beendet, OutputDataReceived, ErrorDataReceived), für einen getrennten Thread aufgerufen werden.Process.Start
inTask.Run
. Ein UNC-Pfad wird beispielsweise synchron aufgelöst. Dieser Ausschnitt kann bis zu 30 Sekunden dauern:Process.Start(@"\\live.sysinternals.com\whatever")
Hier ist meine Einstellung , basierend auf der Antwort von svick . Es fügt eine Umleitung der Ausgabe, eine Beibehaltung des Exit-Codes und eine etwas bessere Fehlerbehandlung hinzu (Entsorgen des
Process
Objekts, auch wenn es nicht gestartet werden konnte):quelle
async Task<int> RunProcessAsync(string fileName, string args)
. Ich habe dieses Beispiel angepasst und drei Objekte einzeln übergeben. Wie kann ich auf das Sammeln von Ereignissen warten? z.B. bevor meine Bewerbung endet .. vielen DankDispose
dass der Ereignishandler auf Null gesetzt wird. Wenn Sie alsoDispose
die Referenz aufrufen, aber behalten, glaube ich, dass dies ein Leck wäre. Wenn jedoch keine Verweise mehr auf dasProcess
Objekt vorhanden sind und es (Müll) gesammelt wird, gibt es niemanden, der auf die Ereignishandlerliste verweist. Es wird also gesammelt, und jetzt gibt es keine Verweise auf die Delegierten, die früher in der Liste waren, sodass sie schließlich Müll gesammelt bekommen.Dispose
werden einige Ressourcen bereinigt, aber es wird nicht verhindert, dass eine durchgesickerte Referenz in der Nähe bleibtprocess
. Sie werden feststellen, dassprocess
sich dies auf die Handler bezieht, der Handler jedochExited
auch aufprocess
. In einigen Systemen würde diese Zirkelreferenz die Speicherbereinigung verhindern, aber der in .NET verwendete Algorithmus würde es dennoch ermöglichen, alles zu bereinigen, solange alles auf einer "Insel" ohne externe Referenzen lebt.Hier ist ein anderer Ansatz. Ähnliches Konzept wie die Antworten von svick und Ohad, jedoch unter Verwendung einer Erweiterungsmethode für den
Process
Typ.Verlängerungsmethode:
Beispiel für einen Anwendungsfall in einer enthaltenen Methode:
quelle
Ich habe eine Klasse aufgebaut, um einen Prozess zu starten, und sie ist in den letzten Jahren aufgrund verschiedener Anforderungen gewachsen. Während der Verwendung habe ich einige Probleme mit der Process-Klasse beim Entsorgen und sogar Lesen des ExitCodes festgestellt. Das ist also alles von meiner Klasse festgelegt.
Die Klasse hat mehrere Möglichkeiten, zum Beispiel das Lesen der Ausgabe, das Starten als Administrator oder ein anderer Benutzer, das Abfangen von Ausnahmen und das Starten all dieser asynchronen Inkl. Stornierung. Schön ist, dass das Lesen der Ausgabe auch während der Ausführung möglich ist.
quelle
Ich denke, alles, was Sie verwenden sollten, ist Folgendes:
Anwendungsbeispiel:
quelle
CancellationToken
bringt es , ein zu akzeptieren , wenn das Abbrechen nichtKill
der Prozess ist?CancellationToken
in derWaitForExitAsync
Methode wird einfach benötigt, um eine Wartezeit abbrechen oder eine Zeitüberschreitung einstellen zu können. Das Beenden eines Prozesses kann erfolgen inStartProcessAsync
: `` `try {await process.WaitForExitAsync (cancellationToken); } catch (OperationCanceledException) {process.Kill (); } `` `CancellationToken
nach sollte das Abbrechen des Tokens zum Abbrechen des Vorgangs führen, wenn eine Methode a akzeptiert , und nicht zum Abbrechen des Wartens. Dies würde der Aufrufer der Methode normalerweise erwarten. Wenn der Anrufer nur das Warten abbrechen und den Vorgang weiterhin im Hintergrund ausführen möchte, ist dies recht einfach extern ( hier ist eine ErweiterungsmethodeAsCancelable
, die genau das tut).Ich bin wirklich besorgt über die Entsorgung des Prozesses, was ist mit dem Warten auf asynchrones Beenden? Dies ist mein Vorschlag (basierend auf dem vorherigen):
Verwenden Sie es dann folgendermaßen:
quelle