J'ai un serveur Web et il y a un travail périodique qui fusionne et envoie des enregistrements (beaucoup de journaux de demandes).
Task.Run(() =>
{
while (true)
{
try
{
MergeAndPutRecords();
}
catch (Exception ex)
{
Logger.Error(ex);
}
}
});
Dans la fonction MergeAndPutRecords
, il y a des enregistrements de code en fusion et une fonction asynchrone renvoie des enregistrements d'envoi de tâches. (En réalité, il s'agit de PutRecordBatchAsync . D'Amazon Kinesis Firehose.)
Alors que se passe-t-il si j'appelle cette fonction sans mot-clé wait? La fonction fonctionne-t-elle sur un fil séparé? Ici dit que ce n'est pas . Alors qu'est-ce que renvoyer la tâche signifie? Ici dit la méthode asynchrone sans mot-clé wait signifie
- Démarre la méthode asynchrone sur le thread actuel. Ignore tous les résultats (y compris les exceptions).
Ensuite, mon travail périodique et PutRecordBatchAsync sont traités simultanément? Je sais asynchronouse et concurrent est différent. Mais il n'y a pas de mot-clé wait et ils sont dans le même fil. Lequel serait exécuté en premier? Je suis déroutant ...
Il y aurait des enregistrements massifs qui doivent être fusionnés et envoyés en temps réel. Je pense donc que cela doit être exécuté simultanément.
Ensuite, mon travail périodique et PutRecordBatchAsync sont traités simultanément?
À l'aide de l'API de tâche, vous pouvez vous assurer qu'elles sont exécutées simultanément (à l'aide du pool de threads), mais vous devez comprendre la différence entre les opérations simultanées en mémoire Vs IO accès simultané basé.
Tandis que la simultanéité en mémoire est bénéfique avec l’utilisation de Tasks, IO l’appel une fois exécuté n’a pas du tout besoin de thread, car il repose sur une simultanéité matérielle, si jamais il utilisait le thread, tout ce que cela ferait d’attendre IO appel à retourner, gaspillant ainsi les précieuses ressources système et réduisant l'évolutivité du système
Votre cas est que IO accès simultané, lorsque vous appelez une API réseau/distante, en quoi async-wait vous aide-t-il ici?
Bien que l'opération async libère le contexte du thread. Sous Windows, elle utiliserait IO port d'achèvement (mécanisme de mise en file d'attente) pour exécuter l'appel Async, tandis que le thread appelant est utilisé pour acheminer d'autres appels similaires. il faut un contexte de thread au retour de l'appel IO pour servir la réponse; pour cela aussi, s'il ne s'agit pas d'un appel d'interface utilisateur, utilisez ConfigureAwait(false)
, de sorte que tout contexte de thread puisse être utilisé pour livrer la réponse.
Que faire si vous n'utilisez pas wait avec async?
L'appel censé être asynchrone devient synchrone et aurait un impact immédiat sur l'évolutivité du système, car les threads sont maintenant bloqués, ce qui est encore pire pour une opération longue IO. Avez-vous déjà vu comment les frameworks JavaScript font toujours un appel AJAX (asynchrone) à l'API du serveur, ce qui permet de beaucoup plus de travail sans bloquer les threads du navigateur.
En général, pour le traitement en mémoire, vous créez un certain nombre de tâches et les traitez avec Task.WaitAll
ou Parallel.ForEach
pour une collection. Pour le traitement asynchrone, la recommandation idéale est de ne pas avoir de Task.Run
n'importe où, mais de préférer Async
à partir du point d'entrée, C'est possible dans le cas de MVC, les contrôleurs peuvent être asynchrones. Plusieurs appels sont regroupés à l'aide de Task.WhenAll
représentant Tâche, puis attendus. même si vous utilisez Task.Run
comme dans votre code, utilisez async lambda
pour exécuter un appel asynchrone
Résumé :
Il est obligatoire d'utiliser await
pour les appels asynchrones. Sinon, le mot clé async
est inutile dans ce contexte et yes await
attendra que l'appel IO soit de retour avant l'exécution de la poursuite, même si aucun thread n'est bloqué dans le processus.
Si une méthode renvoie Task
, il est toujours recommandé d'observer le résultat de cette Task
à un moment donné. Il peut s'agir de la valeur de retour déclarée ou d'une exception. Si vous souhaitez observer cette tâche avant que votre méthode ne continue, await
est la recommandation.
Dans ce cas, vous devriez probablement observer le résultat de Task
renvoyé par PutRecordBatchAsync
. Vous voudrez savoir si l'appel a échoué pour une raison quelconque, car cela indique probablement que vos enregistrements n'ont pas été stockés!
Dans l'exemple de code que vous avez donné, vous constaterez que vous passez des appels ultérieurs à MergeAndPutRecords
avant la fin de l'appel précédent. Êtes-vous sûr que cela est prévu?