如何等待不遵循任何异步模式的{I / O阻塞调用

时间:2017-12-03 21:33:32

标签: .net async-await

在我看过的每个展示中都使用async / await进行I / O阻塞调用,最后有一个虚拟调用(Task.Delay)或一个支持某些异步的API图案。但是,如果你有一个API有I / O阻塞方法,但是没有提供任何你可以等待或以某种方式包装的东西,以便你可以等待它呢?我知道TaskCompletionSource应该是解决这个问题的方法,但是我还没有发现任何真正解释它(无论如何)它是如何工作的。我试过了

var tcs = new TaskCompletionSource<SomeType>();
try
{
  tcs.SetResult(IoBlockingCall());
}
catch (Exception ex)
{
  tcs.SetException(ex);
}
return tcs.Task;

上面的代码在tcs.SetResult()之后立即返回的意义上不起作用。很明显我错过了一些东西,但我还没有找到一个如何做到这一点的例子,它不依赖于你已经有一个方法在启动一些I / O阻塞操作后立即返回。我猜一个问同样问题的简单方法是,如果我不得不写SqlConnection.OpenAsync,我该怎么办?

(注意,请不要回答Task.Run()。这是关于I / O阻塞,而不是卸载。谢谢!)

对于其他评论者,我在这里想要完成的是启动另一个线程。这样做是微不足道的,但是会破坏async / await的主要目的是阻止I / O. (见There Is No Thread)。这让我觉得如果不突破.NET的底部就可能是不可能的,而根据@PetSerAl就是这样。

1 个答案:

答案 0 :(得分:-3)

那是聊天Task.Yield

你可以试试这个:

Task.Yield();
var tcs = new TaskCompletionSource<SomeType>();
try
{
  tcs.SetResult(IoBlockingCall());
}
catch (Exception ex)
{
  tcs.SetException(ex);
}
return tcs.Task;

但这可能无法按预期工作(请阅读文档中的备注部分)。在某些情况下,Task.Delay(0)会更有效。

由于IoBlockingCall正在阻止,因此对于大多数意图和目的,您需要卸载它。或者不是,就像在ASP.NET中卸载没有任何好处一样。