web-dev-qa-db-fra.com

Task.Factory.StartNew vs Task.Factory.FromAsync

Supposons que nous ayons une méthode liée aux E/S (telle qu'une méthode faisant des appels DB). Cette méthode peut être exécutée de manière synchrone et asynchrone. C'est,

  1. Sync:

    IOMethod()
    
  2. Async:

    BeginIOMethod()
    EndIOMethod()
    

Ensuite, lorsque nous exécutons la méthode de différentes manières, comme indiqué ci-dessous, quelle est la différence de performances en termes d'utilisation des ressources?

  1. var task = Task.Factory.StartNew(() => { IOMethod(); });
    task.Wait();
    
  2. var task = Task.Factory.FromAsync(BeginIOMethod, EndIOMethod, ... );
    task.Wait();
    
41
soleiljy
var task = Task.Factory.StartNew(() => { IOMethod(); });
task.Wait();

Cela bloquera un thread de pool de threads pendant l'exécution de IOMethod() et bloquera également votre thread actuel en raison de Wait(). Nombre total de threads bloqués: 2.

var task = Task.Factory.FromAsync(BeginIOMethod, EndIOMethod, ... );
task.Wait();

Cela effectuera (très probablement) l'opération de manière asynchrone sans utiliser de thread, mais cela bloquera le thread actuel en raison de la fonction Wait(). Nombre total de threads bloqués: 1.

IOMethod();

Cela bloquera le thread en cours pendant l'exécution de IOMethod(). Nombre total de threads bloqués: 1.

Si vous devez bloquer le thread actuel, ou si le blocage vous convient, alors vous devriez l'utiliser, car essayer d'utiliser TPL ne vous donnera rien.

var task = Task.Factory.FromAsync(BeginIOMethod, EndIOMethod, ... );
await task;

Cela effectuera l'opération de manière asynchrone sans utiliser de thread, et attendra également que l'opération se termine de manière asynchrone, grâce à await. Nombre total de threads bloqués: 0.

C'est ce que vous devez utiliser si vous souhaitez profiter de l'asynchronie et que vous pouvez utiliser C # 5.0.

var task = Task.Factory.FromAsync(BeginIOMethod, EndIOMethod, ... );
task.ContinueWith(() => /* rest of the method here */);

Cela exécutera l'opération de manière asynchrone sans utiliser de thread, et attendra également que l'opération se termine de manière asynchrone, grâce à ContinueWith(). Nombre total de threads bloqués: 0.

C'est ce que vous devez utiliser si vous souhaitez profiter de l'asynchronie et que vous ne pouvez pas utiliser C # 5.0.

65
svick

(1) entraînera (probablement) le pool de threads .NET pour traiter votre Task.

(2) utilisera le mécanisme que votre paire BeginIOMethod/EndIOMethod utilise nativement pour gérer la partie asynchrone, qui peut ou non impliquer le pool de threads .NET.

Par exemple, si votre BeginIOMethod envoie un message TCP sur Internet et que le destinataire va ultérieurement vous envoyer un message TCP en réponse ( reçu par EndIOMethod), la nature asynchrone de l'opération n'est pas fournie par le pool de threads .NET. La bibliothèque TCP utilisée fournit la partie asynchrone.

Cela peut être accompli en utilisant la classe TaskCompletionSource . Task.Factory.FromAsync Peut créer un TaskCompletionSource<T>, Renvoyer son Task<T>, Puis utiliser EndIOMethod comme déclencheur pour placer le Result dans le Task<T> Qui a été retourné sous la forme Task.Factory.FromAsync Au moment de l'appel.

Quelle est la différence de performances en termes d'utilisation des ressources?

La différence entre (1) et (2) est principalement de savoir si le pool de threads .NET va voir sa charge de travail ajoutée ou non. En général, la bonne chose à faire est de choisir Task.Factory.FromAsync Si vous n'avez qu'une paire Begin.../End... Et Task.Factory.StartNew Sinon.


Si vous utilisez C # 5.0, vous devez utiliser le await task; Non bloquant au lieu de task.Wait();. (Voir la réponse de svick.)

1
Timothy Shields