等待工作,但调用task.Result挂起/死锁

我有以下四个testing,最后一个挂起时,我运行它,我的问题是为什么会发生这种情况:

[Test] public void CheckOnceResultTest() { Assert.IsTrue(CheckStatus().Result); } [Test] public async void CheckOnceAwaitTest() { Assert.IsTrue(await CheckStatus()); } [Test] public async void CheckStatusTwiceAwaitTest() { Assert.IsTrue(await CheckStatus()); Assert.IsTrue(await CheckStatus()); } [Test] public async void CheckStatusTwiceResultTest() { Assert.IsTrue(CheckStatus().Result); // This hangs Assert.IsTrue(await CheckStatus()); } private async Task<bool> CheckStatus() { var restClient = new RestClient(@"https://api.test.nordnet.se/next/1"); Task<IRestResponse<DummyServiceStatus>> restResponse = restClient.ExecuteTaskAsync<DummyServiceStatus>(new RestRequest(Method.GET)); IRestResponse<DummyServiceStatus> response = await restResponse; return response.Data.SystemRunning; } 

我使用这个扩展方法restsharp RestClient :

 public static class RestClientExt { public static Task<IRestResponse<T>> ExecuteTaskAsync<T>(this RestClient client, IRestRequest request) where T : new() { var tcs = new TaskCompletionSource<IRestResponse<T>>(); RestRequestAsyncHandle asyncHandle = client.ExecuteAsync<T>(request, tcs.SetResult); return tcs.Task; } } 
 public class DummyServiceStatus { public string Message { get; set; } public bool ValidVersion { get; set; } public bool SystemRunning { get; set; } public bool SkipPhrase { get; set; } public long Timestamp { get; set; } } 

为什么最后的testing挂起?

您遇到了我在博客和MSDN文章中描述的标准死锁情况: async方法试图将其延续安排到正在被Result调用阻止的线程。

在这种情况下,您的SynchronizationContext是NUnit用来执行async voidtesting方法的一个。 我会尝试使用async Tasktesting方法。

通过asynchronous方法获取值:

 var result = Task.Run(() => asyncGetValue()).Result; 

同步调用一个asynchronous方法

 Task.Run( () => asyncMethod()).Wait(); 

由于使用Task.Run,​​将不会发生死锁问题。

你可以避免死锁添加ConfigureAwait(false)到这一行:

 IRestResponse<DummyServiceStatus> response = await restResponse; 

=>

 IRestResponse<DummyServiceStatus> response = await restResponse.ConfigureAwait(false); 

我在我的博客文章asynchronous/等待的陷阱中描述了这个陷阱

您正在使用Task.Result属性阻止UI。 在MSDN文档中他们明确提到,

Result属性是一个阻塞属性,如果在任务完成之前尝试访问它,当前活动的线程将被阻塞,直到任务完成并且值可用。在大多数情况下,您应该通过使用” 等待“来访问该值或者等待直接访问该属性。“

这种情况下的最佳解决scheme是从方法中删除await&async ,并在返回结果时只使用Task 。 这不会搅乱你的执行顺序。

如果您没有获得callback或控制挂断,在调用服务/ APIasynchronous函数。 您必须configuration上下文才能在相同的调用上下文中返回结果。 使用TestAsync()。ConfigureAwait(continueOnCapturedContext:false);

您将只在Web应用程序中面对此问题,但不在Static void main中