Départ méthode async comme Fil ou de la Tâche
Je suis nouveau sur C#
s await/async
et en train de jouer un peu partout.
Dans mon scénario, j'ai un client simple objet qui a une WebRequest
de la propriété. Le client doit envoyer périodiquement vivant, des messages sur le WebRequest
s RequestStream
.
C'est le constructeur du client de l'objet:
public Client()
{
_webRequest = WebRequest.Create("some url");
_webRequest.Method = "POST";
IsRunning = true;
//--> how to start the 'async' method (see below)
}
et la async vivant-expéditeur méthode
private async void SendAliveMessageAsync()
{
const string keepAliveMessage = "{\"message\": {\"type\": \"keepalive\"}}";
var seconds = 0;
while (IsRunning)
{
if (seconds % 10 == 0)
{
await new StreamWriter(_webRequest.GetRequestStream()).WriteLineAsync(keepAliveMessage);
}
await Task.Delay(1000);
seconds++;
}
}
Comment la méthode a commencé?
nouveau Thread(SendAliveMessageAsync).Start();
ou
Tâche.Exécuter(SendAliveMessageAsync); //changer le type de retour à la Tâche
ou
attendent SendAliveMessageAsync(); //échoue puisque le constructeur n'est pas asynchrone
Ma question est plus sur ma compréhension personnelle de await/async
qui, j'imagine, trompe peut-être, en certains points.
La troisième option est de lancer
The 'await' operator can only be used in a method or lambda marked with the 'async' modifier
C'est en effet un feu et oublier tout simplement de démarrer une
Thread
qui envoient des messages actif.Puis
await
est inutile que vous n'êtes pas vraiment intéressé à attendre qu'il termine. Je voudrais simplement utiliser le fil approche alors. Personnellement, je considère que des tâches de plus petites unités de travail qui doit être exécutée de manière asynchrone.Vous ne devriez jamais appel
new StreamWriter(_webRequest.GetRequestStream()).WriteLineAsync(keepAliveMessage)
- attendre ou à raison, comme StreamWriter
est IDisposable
et doivent être éliminés de manière appropriée une fois utilisé. Cette syntaxe ne permet pas d'appel .Dipose()
.Bon et valable. Mais ce n'est pas le code de travail. Le
StreamWriter
est également initialisée dans le constructeur, mais pour des raisons de simplicité ne figurent pas ici.
OriginalL'auteur KingKerosin | 2016-01-15
Vous devez vous connecter pour publier un commentaire.
Je vote pour "none of the above". 🙂
"Fire and forget" est un scénario difficile à gérer correctement. En particulier, la gestion d'erreur est toujours problématique. Dans ce cas,
async void
peut vous surprendre.Je préfère enregistrer explicitement les tâches, si je ne suis pas
await
ing immédiatement:Ce qui permet aux consommateurs de
Client
de détecter et de récupérer les exceptions levées par leSendAliveMessageAsync
méthode.Sur une note de côté, ce modèle est presque l'équivalent de mon "initialisation asynchrone" modèle.
OriginalL'auteur Stephen Cleary
Édité comme réponse précédente était erroné:
C'est dans le constructeur, je pense que vous devez lancer un nouveau fil pour ça. Personnellement, je ne le faire qu'à l'aide de
await
ne fonctionne pas dans les constructeurs.Oups, vous avez raison.
Quelle est la différence entre
Task.Run
etTask.Factory.StartNew
? Ou est-ce juste votre opinion personnelle?Pour être honnête, j'utilise de la Tâche.Usine.StartNew de la force de l'habitude; la Tâche.Courir est un peu un raccourci, donc si vous voulez plutôt utiliser qu'aller droit devant.
OriginalL'auteur John Clifford
Puisque c'est un feu et oublier opération, vous devez le démarrer à l'aide de
Noter que
await
ne pas démarrer un nouveauTask
. C'est juste du sucre syntaxique pour attendre unTask
pour terminer.Un nouveau thread est démarré à l'aide
Task.Run
.Donc à l'intérieur
SendAliveMessageAsync
vous devriez commencer une nouvelle Tâche:await
ne fonctionne pas dans les constructeurs.Mais il est à l'appeler avec
SendAliveMessageAsync();
pas de façon synchrone et, par conséquent, le Constructeur ne reviendra jamais (à cause des méthodeswhile
)?oh wow, comment ai-je pu rater ça. Merci pour le rappel
Oui, cette boucle dans un constructeur est mauvais. Les constructeurs devraient compléter le plus tôt possible et doit jamais risque d'une exception levée.
voir mon edit
OriginalL'auteur Domysee
Voici une option, car vous ne pouvez pas appeler
await
de l'intérieur d'un constructeur.Je voudrais suggérer à l'aide de Microsoft Réactifs de Cadre (NuGet "Rx-Main").
Le code devrait ressembler à ceci:
Ce code gère tout le filage nécessaire et correctement dispose de la
StreamWriter
comme il va.Chaque fois que vous voulez arrêter de les garder avie appelez simplement
_subscription.Dispose()
.OriginalL'auteur Enigmativity
Dans votre code, il n'y a pas besoin de l'aide de async/await, vient de créer un nouveau thread pour effectuer une opération.
À l'aide de
Task.Factory.StartNew(SendAliveMessage, TaskCreationOptions.LongRunning)
pour effectuer l'opération.Si vous voulez vraiment utiliser async/await modèle, il vous suffit d'appeler au constructeur sans attendre modificateur et de l'oublier.
Je pense que c'est pas une bonne idée de mettre en place un long thread en cours d'exécution ou à l'aide async/await modèle. Minuteries peut-être plus approprié dans cette situation.
OriginalL'auteur cFish