2012-07-31 2 views
2

J'ai récemment essayé de comprendre les nouvelles fonctions async/await et Task.Run de C#. Ce faisant, j'ai écrit un code de test simple qui écrit sur la console pour que je puisse voir dans quel ordre les choses arrivent, jetant un Thread.Sleep ici et là pour m'assurer que les choses se passent vraiment dans l'ordre attendu.Thread.Sleep dans Task.Run

Voici un de mes tests

[Test] 
public void TaskRun() 
{ 
    Console.WriteLine("Before"); 
    Task.Run(() => Console.WriteLine(_terminator.IWillBeBack())); 
    Console.WriteLine("After"); 
} 

avec la classe Terminator suivante:

public class Terminator 
{ 
    public string IWillBeBack() 
    { 
     return "I will be back"; 
    } 
} 

De ce que j'attendais résultat le plus probablement Avant, Après, puis Je serai de retour. C'est en effet ce qui arrive. Ensuite, je fais un changement à la méthode IWillBeBack pour lui permettre de dormir pendant 3 secondes. Le code pour cela:

public class Terminator 
{ 
    public string IWillBeBack() 
    { 
     Thread.Sleep(3000); 
     return "I will be back"; 
    } 
} 

J'attend que le résultat soit encore Avant, Après, puis au bout de 3 secondes à nouveau je serai de retour. Ce n'est pas ce qui se passe quand même. Je reçois à la place Avant et Après, mais jamais je serai de retour.

Pourquoi est-ce?

Lorsque je débogue, il passe clairement par le code, dormant et revenant. Je n'ai pas besoin de Thread.Sleep de cette façon dans n'importe quel code de production, mais je voudrais avoir une vague compréhension de pourquoi je serai de retour n'est pas écrit dans la console dans le second cas.

+0

Je m un peu paresseux aujourd'hui, donc je vais juste faire référence à la réponse. J'ai écrit quelque chose sur ce sujet il y a quelques jours qui pourrait aider à comprendre TPL + async/await: http://blog.tedd.no/2012/07/28/asyncawait-http-server-in-c/ –

Répondre

5

Votre test est en cours avant d'essayer d'imprimer "Je reviendrai". Tu ne fais rien pour attendre que ce soit fini. Selon le coureur de test, il est possible que la redirection Console.WriteLine ait été déconnectée dès que le test est terminé.

Si vous voulez voir la fin, changer votre test:

[Test] 
public void TaskRun() 
{ 
    Console.WriteLine("Before"); 
    var task = Task.Run(() => Console.WriteLine(_terminator.IWillBeBack())); 
    Console.WriteLine("After"); 
    task.Wait(); 
} 
+0

Cela a du sens . J'ai fait ton test et ça marche comme prévu maintenant :) – Halvard

+0

Suis-je juste "chanceux" d'écrire "je reviendrai" dans le premier cas alors (comme je ne fais rien pour y attendre non plus)? Dans la chance je veux dire, il arrive d'être capable d'écrire à temps sur la console avant que le test ne soit terminé. – Halvard

+0

@Halvard: Yup. Il est possible que le démontage du test ait un travail «un peu coûteux», ce qui donne l'avantage à votre autre thread. –

1

Si vous utilisez le cadre MS test dans VS 2012, vous pouvez également écrire le test comme celui-ci

[TestMethod] 
public async Task TaskRun() 
{ 
    Console.WriteLine("Before"); 
    Task t = Task.Run(() => Console.WriteLine(IWillBeBack())); 
    Console.WriteLine("After"); 
    await t; 
} 

private string IWillBeBack() 
{ 
    Thread.Sleep(3000); 
    return "I will be back"; 
} 
+0

Je m'attendais à ce que cela fonctionne quand j'ai vu votre code, mais lors de votre test, j'ai obtenu * Avant * et * Après *, mais pas * Je serai de retour *. Autant que j'ai compris la différence entre task.Wait() et attendent la tâche est que les premiers blocs et le second ne le font pas. Cela pourrait-il être la raison pour laquelle le vôtre ne fonctionne pas? (Soit dit en passant, je vois la sortie dans la la fenêtre GUI de test par défaut pour VS 2012 et utiliser le cadre NUnit. Se pourrait-il que je dupé par là?) – Halvard

+0

AFAIK, NUnit ne supporte pas les tests unitaires de 'async'. Je crois que MSTest et xUnit font maintenant. –

+1

MISE À JOUR: Lorsque le commentaire précédent a été écrit, NUnit ne supportait pas les tests unitaires 'async', mais maintenant il le fait. – Halvard