我有以下连接到SignalR Hub的代码
private static async Task StartListening()
{
try
{
var hubConnection = new HubConnection("http://localhost:8080/");
IHubProxy hubProxy = hubConnection.CreateHubProxy("Broadcaster");
hubProxy.On<EventData>("notifyCardAccessEvent", eventData =>
{
Log.Info(string.Format("Incoming data: {0} {1}", eventData.Id, eventData.DateTime));
});
ServicePointManager.DefaultConnectionLimit = 10;
await hubConnection.Start();
Log.Info("Connected");
}
catch (Exception ex)
{
Log.Error(ex);
}
}
在我的Form_Load
方法中,我有这个
StartListening();
然而,Resharper提醒我要考虑应用“等待”#39;操作员调用结果&#34;
所以我这样做了:
Log.Info("Connecting to SignalR hub...");
StartListening().Wait();
Log.Info("Connected!");
但是,这会导致我的UI线程挂起,Connected!
永远不会打印到日志文件中。
所以我的问题是,我应该何时使用Wait()
?我应该使用Wait()的实例和场景是什么,何时不应该使用Wait()
?
答案 0 :(得分:5)
await
不是Wait
。目前还不清楚调用StartListening()
的代码是什么,但有一个选项是await
,如建议的那样:
await StartListening();
但是,在其他一些情况下,最好什么都不做:
StartListening(); // drop the Task on the floor
或者可能使用ContinueWith
进行手动延续。由于StartListening
方法会捕获任何异常,因此忽略返回的Task
并没有任何问题 - 所以您已经拥有了。不过,我建议将其称为StartListeningAsync
。
死锁的原因是如果你使用Wait
,你的UI线程会阻塞等待异步方法完成,但是这个异步方法正在捕获同步上下文,这意味着为了处理每个延续它试图进入UI线程 - 它被阻止...... 就此。
答案 1 :(得分:4)
@MarcGravell有正确的答案;我只想回答这个问题:
所以我的问题是,我什么时候应该使用Wait()?我应该使用Wait()的实例和场景是什么,何时不应该使用Wait()?
混淆来自于Task
类型用于两个几乎完全不同的事物。
Task
最初是作为任务并行库的一部分在.NET 4.0中引入的。通常,您可以使用并行LINQ或Parallel
类进行并行处理(使用下面的Task
类型)。但是,in advanced scenarios, you could use the Task
type directly。 Task.Wait
用于等待完成这些独立任务。
在.NET 4.5中引入async
/ await
时,现有的Task
类型几乎足以用作抽象&#34 ;未来&#34 ;.因此,不要发明一些新的&#34;未来&#34;类型,他们只是略微扩展Task
以作为未来。
这将我们带到今天,其中Task
可以用作:
(还有一点点交叉:您可以将并行工作视为异步,在极少数情况下,例如Console Main
方法,您需要阻止异步任务;但暂时忽略这些。 )
这意味着Task
的API会按这些行分开。 Start
,Wait
,Result
和ContinueWith
等成员非常坚定地站在并行方面。在异步世界中,await
更合适。
我的async
intro底部有一个小表,它有一些新的(异步)等效的旧(并行)方式。
答案 2 :(得分:1)
你好像误解了来自Resharper的消息。您调用了await
方法,而不是应用Task.Wait()
运算符。他们可能看起来很相似,但他们的工作完全不同。
这个不错的答案将提供有关差异的更多信息:https://stackoverflow.com/a/13140963/3465395