Jak sugeruje tytuł, czy istnieje odpowiednik Process.Start
(pozwalający na uruchomienie innej aplikacji lub pliku wsadowego), na który mogę czekać?
Gram z małą aplikacją konsolową i wydawało mi się, że to idealne miejsce do używania async i czekania, ale nie mogę znaleźć żadnej dokumentacji dla tego scenariusza.
Myślę o czymś podobnym:
void async RunCommand()
{
var result = await Process.RunAsync("command to run");
}
c#
async-await
c#-5.0
linkerro
źródło
źródło
Process.Start
jest asynchroniczny i wydaje się, że OP chce wersji synchronicznej.Odpowiedzi:
Process.Start()
tylko rozpoczyna proces, nie czeka, aż się zakończy, więc nie ma sensu go robićasync
. Jeśli nadal chcesz to zrobić, możesz zrobić coś takiegoawait Task.Run(() => Process.Start(fileName))
.Ale, jeśli chcesz asynchronicznie czekać na proces do końca, można użyć do
Exited
zdarzenia razem zTaskCompletionSource
:źródło
process
iprocess.StartInfo
zmienia to, co się dzieje, gdy je uruchamiasz.Start()
. Jeśli na przykład wywołasz.EnableRaisingEvents = true
przed ustawieniemStartInfo
właściwości, jak widać tutaj, wszystko działa zgodnie z oczekiwaniami. Jeśli ustawisz go później, na przykład, aby zachować go razem z.Exited
, mimo że wywołasz go wcześniej.Start()
, nie działa poprawnie -.Exited
uruchamia się natychmiast, zamiast czekać na zakończenie procesu. Nie wiem dlaczego, tylko słowo przestrogi.process.SynchronizingObject
należy ustawić na komponent formularzy, aby uniknąć wywoływania metod obsługujących zdarzenia (takie jak Exited, OutputDataReceived, ErrorDataReceived) w oddzielnym wątku.Process.Start
wTask.Run
. Na przykład ścieżka UNC zostanie rozwiązana synchronicznie.Process.Start(@"\\live.sysinternals.com\whatever")
Oto moje podejście, oparte na odpowiedzi Svicka . Dodaje przekierowanie wyjścia, zachowanie kodu zakończenia i nieco lepszą obsługę błędów (usuwanie
Process
obiektu, nawet jeśli nie można go uruchomić):źródło
async Task<int> RunProcessAsync(string fileName, string args)
. Dostosowałem ten przykład i przekazałem trzy obiekty jeden po drugim. Jak mogę czekać na zwiększające się wydarzenia? na przykład. zanim moje zgłoszenie zostanie zatrzymane ... wielkie dziękiDispose
obsługi zdarzeń, więc teoretycznie, jeśli zadzwoniłeś,Dispose
ale zachowałeś referencję, uważam, że byłby to wyciek. Jednak gdy nie ma już odwołań doProcess
obiektu i zostaje on zebrany (śmieci), nie ma nikogo, kto wskazuje na listę programów obsługi zdarzeń. Jest więc zbierany, a teraz nie ma żadnych odwołań do delegatów, którzy kiedyś znajdowali się na liście, więc w końcu zostają wyrzuceni.Dispose
czyści niektóre zasoby, ale nie zapobiega zatrzymywaniu się wycieku odniesieniaprocess
. W rzeczywistości zauważysz, żeprocess
odnosi się to do programów obsługi, ale programExited
obsługi ma również odniesienie doprocess
. W niektórych systemach to cykliczne odwołanie zapobiegałoby usuwaniu elementów bezużytecznych, ale algorytm używany w .NET nadal pozwalałby to wszystko wyczyścić, o ile wszystko znajduje się na „wyspie” bez zewnętrznych odniesień.Oto inne podejście. Podobna koncepcja do odpowiedzi Svicka i Ohada , ale z zastosowaniem metody rozszerzenia na
Process
typie.Metoda przedłużenia:
Przykład zastosowania w metodzie zawierającej:
źródło
Zbudowałem klasę, aby rozpocząć proces i przez ostatnie lata rosła ona z powodu różnych wymagań. Podczas użytkowania odkryłem kilka problemów z klasą Process podczas usuwania, a nawet czytania ExitCode. Więc to wszystko jest ustalane przez moją klasę.
Klasa ma kilka możliwości, na przykład odczytywanie wyjścia, uruchamianie jako administrator lub inny użytkownik, przechwytywanie wyjątków, a także uruchamianie wszystkich asynchronicznych, w tym. Anulowanie. Fajne jest to, że wyjście odczytu jest również możliwe podczas wykonywania.
źródło
Myślę, że wszystko, czego powinieneś użyć, to:
Przykład użycia:
źródło
CancellationToken
, jeśli anulowanie go nieKill
oznacza?CancellationToken
wWaitForExitAsync
metodzie jest potrzebna po prostu do anulowania oczekiwania lub ustawienia limitu czasu. Zabicie procesu można wykonać wStartProcessAsync
: `` try {await process.WaitForExitAsync (cancellationToken); } catch (OperationCanceledException) {process.Kill (); } ``CancellationToken
, anulowanie tokena powinno skutkować anulowaniem operacji, a nie anulowaniem oczekującego. Tego normalnie oczekiwałby wywołujący metodę. Jeśli dzwoniący chce anulować tylko oczekiwanie i pozwolić, aby operacja nadal działała w tle, jest to dość łatwe do wykonania na zewnątrz ( tutaj jest metoda rozszerzenia,AsCancelable
która właśnie to robi).Naprawdę martwię się o pozbycie się procesu, a co z oczekiwaniem na asynchroniczne wyjście? Oto moja propozycja (na podstawie poprzedniej):
Następnie użyj tego w ten sposób:
źródło