异步任务挂起

3

I have the following code:

public async Task SendPushNotificationAsync(string username, string message)
{
    var task = ApnsNotifications.Instance.Hub.SendAppleNativeNotificationAsync(alert, username);
    if (await Task.WhenAny(task, Task.Delay(500)) == task) {
       return true;
    }
    return false;
}

我注意到SendAppleNativeNotificationAsync一直挂起(从未返回包含方法),所以我尝试在500毫秒后告诉它取消。但是...现在调用WhenAny也会挂起,我从未看到return被触发,导致消费者无限期等待(这是一个同步方法调用异步方法,所以我调用.Wait()):
_commService.SendPushNotificationAsync(user.Username, notificationDto.PushContent).Wait(TimeSpan.FromSeconds(1));

如何在一定时间内强制结束这个任务,无论发生什么?

如果我只是“点火并忘记”,而不是等待任务完成,会发生什么?


你在哪里执行这段代码?我的意思是,是在Web应用程序、桌面应用程序还是移动设备上? - Evk
@Evk 这是在一个服务方法中调用的,该服务方法由一个 WebApi 控制器调用,并从同步服务方法中调用。 - SB2055
2
永远不要在带有“UI”或“请求”线程的环境中同时使用Wait(或Task.Result)和async\await - 它会像您观察到的那样死锁。 - Evk
@Evk 这是“死锁”还是“阻塞直到某些事情完成”? - SB2055
这是死锁,但我无法在注释中解释原因,你可以在重复的问题中看到它们。 - Evk
1个回答

5

这是一个同步方法调用异步方法,所以我调用了.Wait()

这就是你的问题。你正在死锁,因为你在阻塞异步代码

最好的解决方案是使用await而不是Wait

await _commService.SendPushNotificationAsync(user.Username, notificationDto.PushContent);

如果你绝对不能使用await,那么你可以尝试我《Brownfield Async》文章中描述的其中一种方法。

谢谢。如果我使用await并且SendAppleNativeNotificationAsync从未返回,那么我会没问题吗? - SB2055
@SB2055:为什么它永远不会返回? - Stephen Cleary
我基于我从调试器中观察到的行为得出这个结论 - 我永远无法捕获一个 return,但也许是因为另一个线程正在接收它? - SB2055
1
@SB2055:如果阻塞它,将会阻止完成。如果你使用await,它应该可以正常工作。 - Stephen Cleary
@StephenCleary 我在一个异步方法中遇到了这个确切的问题。当在 await 处设置断点时,尽管消息已传递到端点,但任务挂起,下一行代码从未被调用。 - Philipp Sumi
我在异步方法中也遇到了完全相同的问题。当在等待处设置断点时,尽管消息已传递到端点,但任务挂起,下一行代码从未被调用。 - Qasim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接