C# 为什么等待任务有时会阻塞?
我想我对异步/等待对的工作方式有一个普遍的误解。我使用的是EasyNetQ方法(C#中RabbitMQ的接口),我尝试调用我创建的以下方法:C# 为什么等待任务有时会阻塞?,c#,async-await,easynetq,C#,Async Await,Easynetq,我想我对异步/等待对的工作方式有一个普遍的误解。我使用的是EasyNetQ方法(C#中RabbitMQ的接口),我尝试调用我创建的以下方法: public Task<U> RequestDirectReply<T, U>(T request, int timeout) where T : class where U : class { using (var bus = RabbitHutch.CreateBus($"virtualHost=MyVirtualHos
public Task<U> RequestDirectReply<T, U>(T request, int timeout) where T : class where U : class
{
using (var bus = RabbitHutch.CreateBus($"virtualHost=MyVirtualHost;timeout={timeout};host=MyHostName"))
{
return bus.RequestAsync<T, U>(request);
}
}
public Task RequestDirectReply(T请求,int超时),其中T:class,其中U:class
{
使用(var bus=RabbitHutch.CreateBus($“virtualHost=MyVirtualHost;timeout={timeout};host=MyHostName”))
{
返回bus.RequestAsync(请求);
}
}
现在我理解了这一点,我应该能够调用这个方法,从RequestAsync获取一个任务,然后做一些事情,然后在完成这些事情后等待该任务。大概是这样的:
Task<Reply> task = RequestDirectReply<Request, Reply>(msg, 10);
for (int i = 0; i < 1000000000; ++i)
{
// Hi, I'm counting to a billion
}
var reply = await task;
Task Task=RequestDirectReply(msg,10);
对于(int i=0;i<100000000;++i)
{
//嗨,我数到十亿了
}
var reply=等待任务;
但是,程序会在调用RequestAsync时阻塞超时时间,而不是在等待时阻塞。然后等待立即抛出超时异常
为了确定我是否有误解,我还尝试了以下方法:
public async Task<U> RequestDirectReply<T, U>(T request, int timeout) where T : class where U : class
{
using (var bus = RabbitHutch.CreateBus($"virtualHost=MyVirtualHost;timeout={timeout};host=MyHostName"))
{
return await bus.RequestAsync<T, U>(request);
}
}
public async Task RequestDirectReply(T request,int timeout)其中T:class其中U:class
{
使用(var bus=RabbitHutch.CreateBus($“virtualHost=MyVirtualHost;timeout={timeout};host=MyHostName”))
{
返回wait bus.RequestAsync(请求);
}
}
同样的事情。它在RequestAsync上阻塞。这与常规的阻塞同步调用有何不同?
async
不保证代码实际将异步运行或不会阻塞调用线程。理想情况下,它应该立即启动操作并按预期返回调用方,但有时(即使在现有的.Net Framework方法中)步骤也不是完全异步的
样本:
async Task<int> MyAsync()
{
Thread.Sleep(1000); // (1) sync wait on calling thread
await Task.Delay(1000); // (2) async wait off calling thread
Thread.Sleep(1000); // (3) sync wait likely on original thread
}
async任务MyAsync()
{
Thread.Sleep(1000);//(1)调用线程时同步等待
等待任务。延迟(1000);/(2)异步等待调用线程
Thread.Sleep(1000);//(3)原始线程上可能存在同步等待
}
Sleep
总是阻止调用线程。要等待的任务在第一个await
调用async
方法后返回。这是您可能观察到的案例的演示假设您使用的是
async/await
模式,这样的问题通常是您使用的第三方代码的错误
您正在进行的
RequestAsync()
调用被委托给Rpc.Request(…)
方法,该方法在返回任务之前要做大量的工作。我最好的猜测是,它所做的一些涉及计时器的工作最终会阻塞,这意味着对方法本身的调用也会阻塞。这可能是RequestAsync
中的一个问题。为了简单起见,让我们假设其中有一个Thread.Sleep(10000),然后它自己进行异步调用。在这种情况下,您的请求呼叫将被阻塞10秒。因此,你将不得不进一步投资。可能它正在尝试同步打开连接,但由于超时而失败。最后的代码示例更好。在第一个例子中,完全可以在完成之前进行处理。Alexei的回答是正确的。但是,当您在某些API中遇到这种情况时,您可以通过添加await Task.Yield()来强制API退出线程
beforereturn wait bus.RequestAsync
。好的,在查看代码之后,这似乎就是问题所在。结果表明,RequestAsync会在超时期间阻塞。如果我将超时设置为60,它会阻塞一分钟。如果我把它设为1,它会阻塞一秒钟。这有点违背了它的异步性。我想我会用Rx扩展来表示我的超时时间或其他什么…。@C.Williamson:我建议在你的库的GitHub页面上也粘贴一个问题。作者可能没有意识到他们的异步代码是阻塞的。