简体   繁体   English

在C#中使用返回值同步运行异步方法的问题

[英]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方法将一直阻塞,直到该调用完成
  • the rest of the method is just offloaded to a different thread, so there is no real benefit other than to avoid blocking the caller 该方法的其余部分仅被卸载到其他线程,因此除了避免阻塞调用方之外,没有其他实际好处。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM