without run practices method best await async c# nunit task deadlock async-await

run - c# async task best practices



aguarda el trabajo pero llama a task.Result cuelga/deadlocks (5)

Tengo las siguientes cuatro pruebas y la última se cuelga cuando la ejecuto, mi pregunta es por qué sucede esto:

[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; }

Yo uso este método de extensión para 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; } }

¿Por qué se cuelga la última prueba?


Adquirir un valor a través de un método asíncrono:

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

Llamando Syncrono a un método asíncrono

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

No se producirán problemas de interbloqueo debido al uso de Task.Run.


Está bloqueando la UI mediante la propiedad Task.Result. En MSDN Documentation , han mencionado claramente que,

"La propiedad Result es una propiedad de bloqueo. Si intenta acceder antes de que su tarea finalice, la secuencia actualmente activa se bloquea hasta que la tarea finalice y el valor esté disponible. En la mayoría de los casos, debe acceder al valor usando Await. o espera en lugar de acceder a la propiedad directamente ".

La mejor solución para este escenario sería eliminar tanto await como async de los métodos y usar solo Tarea en la que está devolviendo el resultado. No arruinará tu secuencia de ejecución.


Puede evitar el interbloqueo agregando ConfigureAwait(false) a esta línea:

IRestResponse<DummyServiceStatus> response = await restResponse;

=>

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

Describí este error en mi publicación de blog. Errores de async / await


Si no recibe devoluciones de llamada o el control se cuelga, después de llamar a la función de servicio / API Async. Debe configurar Contexto para devolver el resultado en el mismo contexto llamado. Use TestAsync (). ConfigureAwait (continueOnCapturedContext: false);

Te enfrentarás a este problema solo en aplicaciones web, pero no en Static void main


Te encuentras con la situación estándar de punto muerto que describo en mi blog y en un artículo de MSDN : el método async está intentando programar su continuación en un hilo que está siendo bloqueado por la llamada a Result .

En este caso, su SynchronizationContext es el utilizado por NUnit para ejecutar métodos de prueba de async void . Intentaría usar métodos de prueba async Task lugar.