J'utilise un client API complètement asynchrone, c'est-à-dire que chaque opération retourne Task
ou Task<T>
, par exemple:
static async Task DoSomething(int siteId, int postId, IBlogClient client)
{
await client.DeletePost(siteId, postId); // call API client
Console.WriteLine("Deleted post {0}.", siteId);
}
En utilisant les opérateurs asynchrones / attendent C # 5, quelle est la façon correcte / la plus efficace de démarrer plusieurs tâches et d'attendre qu'elles se terminent toutes:
int[] ids = new[] { 1, 2, 3, 4, 5 };
Parallel.ForEach(ids, i => DoSomething(1, i, blogClient).Wait());
ou:
int[] ids = new[] { 1, 2, 3, 4, 5 };
Task.WaitAll(ids.Select(i => DoSomething(1, i, blogClient)).ToArray());
Étant donné que le client API utilise HttpClient en interne, je m'attends à ce que cela émette 5 requêtes HTTP immédiatement, écrivant sur la console à mesure que chacune se termine.
c#
.net
task-parallel-library
async-await
c#-5.0
Ben Foster
la source
la source
Réponses:
Bien que vous exécutiez les opérations en parallèle avec le code ci-dessus, ce code bloque chaque thread sur lequel chaque opération s'exécute. Par exemple, si l'appel réseau prend 2 secondes, chaque thread se bloque pendant 2 secondes sans rien faire mais attendre.
D'un autre côté, le code ci-dessus
WaitAll
bloque également les threads et vos threads ne seront pas libres de traiter tout autre travail jusqu'à la fin de l'opération.Approche recommandée
Je préférerais
WhenAll
qui effectuera vos opérations de manière asynchrone en parallèle.Pour sauvegarder cela, voici un article de blog détaillé retraçant toutes les alternatives et leurs avantages / inconvénients: Comment et où les E / S asynchrones simultanées avec l'API Web ASP.NET
la source
WaitAll
bloque également les threads" - ne bloque-t-il pas seulement un thread, celui qui a appeléWaitAll
?J'étais curieux de voir les résultats des méthodes fournies dans la question ainsi que la réponse acceptée, alors je l'ai mise à l'épreuve.
Voici le code:
Et la sortie résultante:
la source
Étant donné que l'API que vous appelez est asynchrone, la
Parallel.ForEach
version n'a pas beaucoup de sens. Vous ne devriez pas utiliser.Wait
dans laWaitAll
version car cela perdrait le parallélisme Une autre alternative si l'appelant utilise asyncTask.WhenAll
après avoir faitSelect
etToArray
pour générer le tableau de tâches. Une deuxième alternative utilise Rx 2.0la source
Vous pouvez utiliser la
Task.WhenAll
fonction que vous pouvez passer n tâches;Task.WhenAll
renverra une tâche qui s'exécute jusqu'à la fin lorsque toutes les tâches que vous avez passées pour seTask.WhenAll
terminer. Vous devez attendre de manière asynchroneTask.WhenAll
pour ne pas bloquer votre thread d'interface utilisateur:la source
Parallel.ForEach
nécessite une liste de travailleurs définis par l'utilisateur et un non asynchroneAction
pour effectuer avec chaque travailleur.Task.WaitAll
etTask.WhenAll
nécessitent unList<Task>
, qui sont par définition asynchrones.J'ai trouvé la réponse de RiaanDP très utile pour comprendre la différence, mais elle a besoin d'une correction pour . Pas assez de réputation pour répondre à son commentaire, donc ma propre réponse.
Parallel.ForEach
La sortie résultante est ci-dessous. Les délais d'exécution sont comparables. J'ai effectué ce test pendant que mon ordinateur effectuait l'analyse antivirus hebdomadaire. Changer l'ordre des tests a changé les temps d'exécution sur eux.
la source