[英]Problems running async method with return value synchronously in C#
I'm trying to write a hardware library in C# using the async / await features. 我正在尝试使用async / await功能在C#中编写硬件库。 For many operations, there will be two methods, one that runs asynchronously, and another one running the asynchronous method synchronously.
对于许多操作,将有两种方法,一种是异步运行的,另一种是异步运行的。 For example, consider this:
例如,考虑一下:
public override bool ReferenceRun(bool positiveDirection) {
var runTask = ReferenceRunAsync(positiveDirection);
return runTask.Result;
}
public override async Task<bool> ReferenceRunAsync(bool positiveDirection) {
String cmd = createAxisCommand(positiveDirection ? refRunPlusCmd : refRunMinusCmd);
bool writeOK = writeToCOMPort(cmd);
if ( !writeOK ) return false;
return await Task.Factory.StartNew(() => {
WaitForHalt();
return setParameter(postitionParam, 0);
});
}
Form this and that answers, I suspected that it was ok to call runTask.Result
in order to wait for the async method to complete and then retrieve the result. 以此 为答案,我怀疑可以调用
runTask.Result
以便等待异步方法完成然后检索结果。 However, when I run the code, the call to ReferenceRun
does never return. 但是,当我运行代码时,对
ReferenceRun
的调用永远不会返回。 When I pause execution in the debugger, I can see that it hangs at the return runTask.Result
statement. 当我在调试器中暂停执行时,可以看到它挂在
return runTask.Result
语句上。
What's going on here? 这里发生了什么?
Edit: According to this , the requested behavior can be achieved like this: 编辑:根据此 ,可以这样实现所请求的行为:
public override bool ReferenceRun(bool positiveDirection) {
var runTask = Task<bool>.Run(async () => { return await ReferenceRunAsync(positiveDirection); });
return runTask.Result;
}
In ReferenceRunAsync
, when you use await
, the current synchronization context (typically the UI thread's context) is captured, and the continuation (what follows the await
instruction) is run on that synchronization context. 在
ReferenceRunAsync
,当您使用await
,将捕获当前的同步上下文(通常是UI线程的上下文),并在该同步上下文上运行延续(遵循await
指令的操作)。 But since you are synchronously waiting for the result in ReferenceRun
, the thread is already busy and can't execute the continuation, so you have a deadlock. 但是,由于您正在同步等待
ReferenceRun
的结果,因此该线程已经很忙,无法执行继续操作,因此存在死锁。 An easy fix is to call ConfigureAwait(false)
on the awaited task to avoid capturing the context: 一个简单的解决方法是在等待的任务上调用
ConfigureAwait(false)
以避免捕获上下文:
return await Task.Factory.StartNew(() => {
WaitForHalt();
return setParameter(postitionParam, 0);
}).ConfigureAwait(false);
Anyway, in general you shouldn't expose a synchronous wrapper for an asynchronous method, or the other way round. 无论如何,通常不应该为异步方法公开同步包装,反之亦然。 See Stephen Toub's explanations:
请参阅Stephen Toub的解释:
Another issue with your code is that ReferenceRunAsync
isn't really synchronous, because: 您的代码的另一个问题是
ReferenceRunAsync
并非真正同步,因为:
writeToCOMPort
is a blocking IO operation (just a guess from the name), so the ReferenceRunAsync
method will block until that call is complete writeToCOMPort
是一个阻塞的IO操作(仅是对名称的猜测),因此ReferenceRunAsync
方法将一直阻塞,直到该调用完成 In this case it would probably be better to just expose a purely synchronous method, and let the caller offload it to another thread if necessary. 在这种情况下,最好公开一个纯粹的同步方法,并在必要时让调用方将其分流到另一个线程。
public override bool ReferenceRun(bool positiveDirection) {
var runTask = ReferenceRunAsync(positiveDirection);
runTask.Wait();
return runTask.Result;}
Try this. 尝试这个。 You need to start the task befor you can use the result.
您需要启动任务,然后才能使用结果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.