Le statut de la tâche des modifications à RanToCompletion si la Tâche attendent quelque chose
La question décrit le même problème trouve ici - MSDN Forum du Développeur. La question n'est pas acceptée réponse, ni aucune des réponses ne peut être appliqué à mon cas (d'où une autre question).
Question est également à l'origine d'un je demandé précédemment, mais, en raison de la nature différente et plus de problème spécifique, je suis en demander un nouveau.
Code complet peut être trouvé ici: http://pastebin.com/uhBGWC5e
* La seule chose qui a changé est l'achèvement de la tâche de vérification (while
-> Task.WhenAll
).
Lors de l'attente d'une opération asynchrone à l'intérieur d'une Tâche, la Tâche modifications de statut de RanToCompletion
même si, la Tâche est encore en cours d'exécution.
Maintenant, nous allons voir la configuration:
//Start async.
Task t1 = Task.Factory.StartNew(Accept, s1);
Task t2 = Task.Factory.StartNew(Accept, s1);
Task.WhenAll(t1, t2).Wait();
La Accept
méthode:
public static async void Accept(object state)
{
TcpListenerEx server = (TcpListenerEx) state;
IPEndPoint endPoint = server.LocalEndpoint as IPEndPoint;
Log("Accepting clients on {0}", endPoint);
while (true)
{
var client = server.AcceptTcpClientAsync();
if (client == null)
{
Log("Null error on accept");
break;
}
TcpClient connected = (TcpClient) client;
servers[server].Add(connected);
bool stop = await Task<Task<bool>>.Factory.StartNew(Listen, connected).Unwrap();
if (stop == true)
{
break;
}
}
//Stop the server.
server.Stop();
Log("Stoppped {0}", endPoint);
}
En raison de TaskStatus changer de RanToCompletion, le Task.WhenAll().Wait()
appel marque elle-même fini assez rapidement, de sorte que le programme sera exécuté par la suite, finalement terminée.
Mais, le Accept
tâche, en théorie, ne devrait jamais s'arrêter, elle est à l'écoute pour les connexions jusqu'explicitement arrêté.
Quel est le problème, ici, à l'origine de la Tâche à être marqué comme RanToCompletion
prématurément?
Task.Factory.StartNew
d'invoquer une méthode asynchrone, plutôt que d'avoir de la méthode de retour d'un Task
?OriginalL'auteur jolt | 2014-05-29
Vous devez vous connecter pour publier un commentaire.
Je peux reproduire ce problème avec beaucoup moins de code:
Mais cela fonctionne correctement:
Fondamentalement, en utilisant
Task.Factory.StartNew()
, vous êtes la création d'unTask
basé sur un thread séparé arriver donné naissance à invoquer le délégué (leAccept()
méthode). LeAccept
méthode elle-même (comme tout bonasync
méthode) renvoie en fait immédiatement. De sorte que le fil qui l'appelle, il termine sa tâche immédiatement, de sorte que leTask
créé pour représenter ce thread termine immédiatement.Si vous le permettez
Accept()
retour d'unTask
au lieu devoid
, puis leTask
qu'il renvoie est ce que vous devriez être en attente si vous voulez attendre jusqu'à ce qu'il a exécuté l'ensemble de sesawait
s.Accept
méthode qui retourne immédiatement, mais la tâche que l'appel se termine dès qu'il appelleAccept
. Et c'est parce queAccept
est défini comme async et la tâche n'est pas nécessaire d'attendre jusqu'à ce qu'il retourne en fait?Bon, en faisant
Accept()
de retourTask
au lieu devoid
et de démarrage sansTask.Factory
a fait leTask.WhenAll
attendre jusqu'à la fin. Le problème maintenant, c'est que la nature deAccept
est cassé (TcpListener) ne répond pas à plus d'une connexion à un temps que les fils sont perdus (comme prévu).Il y a beaucoup de code, et je ne suis pas entièrement sûr de ce que vous allez pour. Pourriez-vous préciser votre problème à quelque chose de plus gérable et poser une nouvelle question?
semble être un bon point ici. Puisqu'il revient la Tâche de<la Tâche>, wrapper tâche de retourner immédiatement après l'intérieure de la tâche commence. À L'Aide De La Tâche.Run() permettra de résoudre ce problème.
OriginalL'auteur StriplingWarrior
Il y a deux choses de mal:
async void
etTâche.Usine.StartNew
. Deux de ces mauvaises pratiques.D'abord,
async void
ne pas autoriser le code appelant pour savoir quand elle se termine. Donc, il n'a pas d'importance qui vous êtes en attente; leasync void
méthode sera de retour assez rapidement, et votre application ne peut pas savoir quandAccept
est réellement terminée. Pour résoudre ce problème, remplacezasync void
avec le beaucoup plus bonasync Task
.Deuxième,
StartNew
ne pas comprendre asynchrone délégués.StartNew
est extrêmement API de bas niveau qui ne doit pas être utilisé dans 99,99% de la production de code. UtilisationTask.Run
à la place.OriginalL'auteur Stephen Cleary