this postへのフォローアップの質問があります。私のバージョンでは、次のことを非同期にしたいと思っています。ここで私が持っているものである:ここではプロセスを実行するC#クラスの非同期メソッド
public virtual Task<bool> ExecuteAsync()
{
var tcs = new TaskCompletionSource<bool>();
string exe = Spec.GetExecutablePath();
string args = string.Format("--input1={0} --input2={1}", Input1, Input2);
try
{
var process = new Process
{
EnableRaisingEvents = true,
StartInfo =
{
UseShellExecute = false,
FileName = exe,
Arguments = args,
RedirectStandardOutput = true,
RedirectStandardError = true,
WorkingDir = CaseDir
}
};
process.Exited += (sender, arguments) =>
{
if (process.ExitCode != 0)
{
string errorMessage = process.StandardError.ReadToEndAsync();
tcs.SetResult(false);
tcs.SetException(new InvalidOperationException("The process did not exit correctly. Error message: " + errorMessage));
}
else
{
File.WriteAllText(LogFile, process.StandardOutput.ReadToEnd());
tcs.SetResult(true);
}
process.Dispose();
};
process.Start();
}
catch (Exception e)
{
Logger.InfoOutputWindow(e.Message);
tcs.SetResult(false);
return tcs.Task;
}
return tcs.Task;
}
}
Spec, Input1, Input2, CaseDir, LogFile
はExecuteAsyncがメソッドであるクラスのすべてのメンバーです。そういうふうに使ってもいいですか?私は苦労していますパーツは以下のとおりです。
-
私はラムダ式で1を持っているのに対し、私は
- プロセスのために。メソッド定義でasyncキーワードが必要なのでしょうか?おそらく非同期的な例を見てきました。 this one。私はそれを取り出してコンパイルしますが、私はこれを非同期で使用できますか?
- ラムダ式でasyncキーワードを使用していて、プロセスのラムダ式内の対応する
await process.StandardError.ReadToEndAsync()
OKですか? this exampleでは、対応する行にasync await
を使用していないので、どうやってそれを取り除いたのだろうか?方法ReadToEnd
がブロックされていると言われて以来、ブロックされていないまま放置しないでください。 - 私は
File.WriteAllText(LogFile, process.StandardOutput.ReadToEnd())
のメソッド呼び出しをブロックすることになっていますか?もしそうなら、どうすればそれを避けることができますか? - 例外処理は意味がありますか?
catch
ブロックで使用したアプリケーションログツールLogger.InfoOutputWindow
の詳細を知っておく必要がありますか? - 最後に、
process.Exited
イベントは、私が出会ったすべての例ではいつもprocess.Start()
の前に表示されますか?process.Exited
イベントの前にprocess.Start()
を置くことはできますか?
await
キーワードを必要とする警告なしにメソッド定義(
public virtual async Task<bool> ExecuteAsync()
)で非同期キーワードを使用するように見えることはできません
あなたの興味のために、どんなアイデアや感謝をお待ちしております。&注目。
EDIT#1:上記の#3のために、私は以下のルネ・フォークト@からのコメントに一部基づいてアイデアを持っていたので、私はのelse {}
ブロック内File.WriteAllText(...)
コールを移動するには、変更を行った
process.Exited
イベント。おそらく、これは#3を扱うでしょう。
EDIT#2:
Iは、元に基づいて変更(コードスニペットは、現在変更されている)、基本的に除去機能定義でasync
キーワードとprocess.Exited
イベントハンドラでawait
キーワードの両方の初期リストを作っ@RenéVogtのコメントまだ最近の彼の最近の変更を試していない。私は実行すると、私は例外を取得:次のように
A plugin has triggered error: System.InvalidOperationException; An attempt was made to transition a task to a final state when it had already completed.
は、アプリケーションログには、コールスタックを持っています
UNHANDLED EXCEPTION:
Exception Type: CLR Exception (v4)
Exception Details: No message (.net exception object not captured)
Exception Handler: Unhandled exception filter
Exception Thread: Unnamed thread (id 29560)
Report Number: 0
Report ID: {d80f5824-ab11-4626-930a-7bb57ab22a87}
Native stack:
KERNELBASE.dll+0x1A06D RaiseException+0x3D
clr.dll+0x155294
clr.dll+0x15508E
<unknown/managed> (0x000007FE99B92E24)
<unknown/managed> (0x000000001AC86B00)
Managed stack:
at System.Threading.Tasks.TaskCompletionSource`1.SetException(Exception exception)
at <namespace>.<MyClass>.<>c__DisplayClass3.<ExecuteAsync>b__2(Object sender, EventArgs arguments)
at System.Diagnostics.Process.RaiseOnExited()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading._ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback(Object state, Boolean timedOut)
この質問は非常に広いようです。同じ質問に5つの異なる質問がありますか?一度に1つのパーツのヘルプを実装、デバッグ、検索する必要があります。あなたは次のものに移動する前に、その部分を働かせることを確認してください。 –
私はRenéに 'ReadToEndAsync()'を呼び出すべきではないことに同意しますが、 'RedirectStandardError'や' RedirectStandardOutput'を決して設定しないで、stdoutストリームとstderrストリームを読み込むためにプロセスが終了するまで待ってくださいプロセスをデッドロックする良い方法です(これは古典的な間違いです:出力ストリームバッファがいっぱいになる、プロセスブロック、コード、プロセスが_exits_のときだけ実行する、ストリームを読み込んでバッファを空にしない) –