【发布时间】:2016-05-20 14:56:34
【问题描述】:
我对@987654321@ 有一个后续问题。在我的版本中,我有以下我想要异步的内容。这是我所拥有的:
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 是其方法的类的所有成员。可以这样使用它们吗?我正在努力的部分是:
- 我似乎无法在方法定义 (
public virtual async Task<bool> ExecuteAsync()) 中使用 async 关键字,而不会警告我需要一个await关键字,而我在该过程的 lambda 表达式中确实有一个。我什至需要在方法定义中使用 async 关键字吗?我见过他们不使用它的所谓异步示例,例如this one。如果我把它拿出来编译,但我可以异步使用它吗? - 我在 lambda 表达式中对 async 关键字的使用以及在进程 lambda 表达式中对应的
await process.StandardError.ReadToEndAsync()是否正常?在this example,他们没有在相应的行使用async await,所以我想知道他们是如何逃脱的?因为有人告诉我ReadToEnd方法正在阻塞,所以不会让它阻塞吗? - 我对@987654332@ 的调用会导致整个方法阻塞吗?如果是这样,如果可能的话,我该如何避免这种情况?
- 异常处理有意义吗?我是否应该知道我在
catch块中使用的应用程序记录器方法Logger.InfoOutputWindow的任何详细信息? - 最后,为什么在我遇到的所有示例中
process.Exited事件总是出现在process.Start()之前?我可以将process.Start()放在process.Exited事件之前吗?
感谢您的任何想法,并提前感谢您的关注和关注。
编辑#1:
对于上面的#3,我有一个想法,部分基于下面@René Vogt 的评论,所以我做了一个更改,将File.WriteAllText(...) 调用移动到else {} 事件的else {} 块内。也许这解决了#3。
编辑 #2:
我制作了最初的更改列表(现在更改了代码 sn-p),基本上删除了函数定义中的 async 关键字和基于来自 @ 的原始 cmets 的 process.Exited 事件处理程序中的 await 关键字勒内·沃格特。尚未在下面尝试他最近的更改。当我运行时,我得到一个异常:
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)
【问题讨论】:
-
这个问题似乎很宽泛。同一个问题有五个不同的问题?您应该一次实施、调试和寻求帮助。在继续下一个之前,请确保该部分正常工作。
-
我同意 René 的观点,即您不应该调用
ReadToEndAsync(),但您还有另外两个问题:您从未设置过RedirectStandardError或RedirectStandardOutput,并等到进程退出再读取stdout 和 stderr 流是使进程死锁的好方法(这是一个典型的错误:输出流缓冲区填充,进程阻塞,您的代码,仅在进程 退出 时运行,永远无法读取流清空缓冲区) -
查看此答案,它可能会帮助您简化代码:stackoverflow.com/a/65804377/1653521
标签: c# asynchronous lambda process task