жду работы, но вызов задачи.Результат зависает / взаимоблокировки
у меня есть следующие четыре теста и последний зависает, когда я запускаю его, мой вопрос, почему это происходит:
[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;
}
Я использую этот метод расширения для RestClient restsharp:
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; }
}
почему последний тест висит?
5 ответов:
вы сталкиваетесь со стандартной тупиковой ситуацией, которую я описываю мой блог и в статье MSDN: the
async
метод пытается запланировать его продолжение на поток, который блокируется вызовомResult
.в этом случае
SynchronizationContext
используется NUnit для выполненияasync void
методы испытаний. Я бы попробовал использовать методы испытаний.
получение значения с помощью асинхронного метода:
var result = Task.Run(() => asyncGetValue()).Result;
синхронный вызов асинхронного метода
Task.Run( () => asyncMethod()).Wait();
из-за использования задачи не возникнет проблем с взаимоблокировкой.Бежать.
вы можете избежать тупикового добавления
ConfigureAwait(false)
на эту строку:IRestResponse<DummyServiceStatus> response = await restResponse;
=>
IRestResponse<DummyServiceStatus> response = await restResponse.ConfigureAwait(false);
Я описал эту ловушку в своем блоге подводные камни асинхронных/ждут
вы блокируете пользовательский интерфейс с помощью задачи.Свойство result. В Примечание они ясно упомянули об этом,
" The результат свойство является блокирующим свойством. Если вы попытаетесь получить к нему доступ прежде чем его задача будет завершена, поток, который в настоящее время активен блокируется до завершения задачи и значение. В большинстве случаи, вы должны получить доступ к значению с помощью ждут или ждут вместо доступ к собственности напрямую."
лучшим решением для этого сценария было бы удалить оба await & async из методов и использовать только задание где вы возвращаете результат. Это не испортит вашу последовательность выполнения.
Если вы не получаете обратных вызовов или управления зависает, после вызова службы / API асинхронной функции. Вы должны настроить контекст, чтобы вернуть результат на том же самом вызванном контексте. Используйте TestAsync ().ConfigureAwait (continueOnCapturedContext: false);
вы будете сталкиваться с этой проблемой только в веб-приложениях, но не в Static void main