même après avoir utilisé ConfigureAwait (false) dans Asp.Net flux
je suis frapper impasse, même après l'utilisation de ConfigureAwait(false)
, ci-dessous le code de l'échantillon.
selon l'échantillon http://blog.stephencleary.com/2012/02/async-and-await.html (contexte # Avoding), cela n'aurait pas dû frapper dead lock.
C'est ma classe:
public class ProjectsRetriever
{
public string GetProjects()
{
...
var projects = this.GetProjects(uri).Result;
...
...
}
private async Task<IEnumerable<Project>> GetProjects(Uri uri)
{
return await this.projectSystem.GetProjects(uri, Constants.UserName).ConfigureAwait(false);
}
}
Cette classe est à partir d'une bibliothèque partagée:
public class ProjectSystem
{
public async Task<IEnumerable<Project>> GetProjects(Uri uri, string userName)
{
var projectClient = this.GetHttpClient<ProjectHttpClient>(uri);
var projects = await projectClient.GetProjects();
// code here is never hit
...
}
si j'ajoute ConfigureAwait(false) pour attendre l'appel dans la bibliothèque partagée, où HttpClient appel est fait:
public class ProjectSystem
{
public async Task<IEnumerable<Project>> GetProjects(Uri uri, string userName)
{
var projectClient = this.GetHttpClient<ProjectHttpClient>(uri);
var projects = await projectClient.GetProjects().ConfigureAwait(false);
// no deadlock, resumes in a new thread.
...
}
j'ai parcouru tous les blogs trouvés, la seule différence que je trouve est ConfigureAwait(false) works lorsqu'il est utilisé avec httpClient.AsyncApi() l'appel!?
s'il vous Plaît aider clarifier!!!
3 réponses
commentaires:
j'étais dans l'hypothèse, une fois ConfigureAwait(false) utilisé (n'importe où dans la pile d'appels), l'exécution à partir de ce point ne causera pas d'impasse.
Je ne crois pas à la magie noire, et vous non plus. Toujours s'efforcer de comprendre ce qui se passe lorsque vous utilisez quelque chose dans votre code.
quand vous await
une méthode asynchrone qui renvoie un Task
et SynchronizationContext par TaskAwaitable
généré par l' Task.GetAwaiter
méthode.
une fois que le contexte de synchronisation est en place et que l'appel de méthode async est terminé, le TaskAwaitable
tente de canaliser la suite (qui est essentiellement le reste des appels de méthode après le premier await
mot clé) sur le SynchronizationContext
(en utilisant SynchronizationContext.Post
) qui a déjà été capturé. Si le thread d'appel est bloqué, en attendant cette même méthode pour finir, vous avez un blocage.
vous devriez demandez-vous dois-je exposer des enveloppes synchrones pour des méthodes asynchrones? 99% du temps la réponse est aucun. Vous devez utiliser une API synchrone, comme celle WebClient
offres.
il bloque lorsqu'il est utilisé dans ProjectsRetriever
parce que:
public class ProjectsRetriever
{
public string GetProjects()
{
//querying the result blocks the thread and wait for result.
var projects = this.GetProjects(uri).Result;
... //require Thread1 to continue.
...
}
private async Task<IEnumerable<Project>> GetProjects(Uri uri)
{
//any thread can continue the method to return result because we use ConfigureAwait(false)
return await this.projectSystem.GetProjects(uri, Constants.UserName).ConfigureAwait(false);
}
}
public class ProjectSystem
{
public async Task<IEnumerable<Project>> GetProjects(Uri uri, string userName)
{
var projectClient = this.GetHttpClient<ProjectHttpClient>(uri);
var projects = await projectClient.GetProjects();
// code here is never hit because it requires Thread1 to continue its execution
// but Thread1 is blocked in var projects = this.GetProjects(uri).Result;
...
}
Il ne bloque pas quand utilisé dans ProjectSystem
parce que:
public class ProjectsRetriever
{
public string GetProjects()
{
...
var projects = this.GetProjects(uri).Result;
...//requires Thread1 to continue
...
}
private async Task<IEnumerable<Project>> GetProjects(Uri uri)
{
//requires Thread1 to continue
return await this.projectSystem.GetProjects(uri, Constants.UserName);
}
}
public class ProjectSystem
{
public async Task<IEnumerable<Project>> GetProjects(Uri uri, string userName)
{
var projectClient = this.GetHttpClient<ProjectHttpClient>(uri);
var projects = await projectClient.GetProjects().ConfigureAwait(false);
// no deadlock, resumes in a new thread. After this function returns, Thread1 could continue to run
}
j'ai eu le même problème. "ConfigureAwait (false)" ne peut pas toujours éviter les serrures mortes.
public class HomeController : Controller
{
public async Task<ActionResult> Index()
{
// This works !
ViewBag.Title = GetAsync().Result;
// This cause deadlock even with "ConfigureAwait(false)" !
ViewBag.Title = PingAsync().Result;
return View();
}
public async Task<string> GetAsync()
{
var uri = new Uri("http://www.google.com");
return await new HttpClient().GetStringAsync(uri).ConfigureAwait(false);
}
public async Task<string> PingAsync()
{
var pingResult = await new Ping().SendPingAsync("www.google.com", 3).ConfigureAwait(false);
return pingResult.RoundtripTime.ToString();
}
}
pour le code ci-dessus, " GetAsync () "fonctionne alors que" PingAsync () " ne fonctionne pas.
mais j'ai trouvé que si j'enroule l'appel async dans une nouvelle tâche, et attend cette tâche, PingAsync () fonctionnera l'événement sans "ConfigureAwait (false)":
var task = Task.Run(() => PingAsync());
task.Wait();
ViewBag.Title = task.Result;
je ne sais pas pourquoi, peut-être quelqu'un peut me dire la différence.