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 de firebase database). 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(); 

 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 à cause de Wait() . Nombre total de threads bloqués: 2.

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

Cela (le plus probable) effectuera l’opération de manière asynchrone sans utiliser de thread, mais bloquera le thread en cours à cause de Wait() . Nombre total de threads bloqués: 1.

 IOMethod(); 

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

Si vous avez besoin de bloquer le thread actuel, ou si le bloquer vous convient, alors vous devriez l’utiliser, parce qu’essayer d’utiliser TPL ne vous donnera réellement rien.

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

Ceci 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 à wait. Nombre total de threads bloqués: 0.

C’est ce que vous devriez utiliser si vous souhaitez tirer parti de l’asynchronisme et que vous pouvez utiliser C # 5.0.

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

Ceci 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 à ContinueWith() . Nombre total de threads bloqués: 0.

C’est ce que vous devriez utiliser si vous souhaitez tirer parti de l’asynchronisme et que vous ne pouvez pas utiliser C # 5.0.

(1) obligera (probablement) le pool de threads .NET à traiter votre Task .

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

Par exemple, si votre BeginIOMethod envoie un message TCP sur Internet et que le destinataire vous envoie ultérieurement 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 à l’aide de la classe TaskCompletionSource . Task.Factory.FromAsync peut créer une TaskCompletionSource , renvoyer sa Task , puis utiliser EndIOMethod comme déclencheur pour placer le Result dans la Task renvoyée sous la forme Task.Factory.FromAsync au moment de l’appel. .

Quelle est la différence de performance en termes d’utilisation des ressources?

La différence entre (1) et (2) réside principalement dans le fait que la charge de travail du pool de threads .NET doit être ajoutée ou non. En général, la bonne chose à faire est de choisir Task.Factory.FromAsync si vous avez uniquement une paire Begin... / End... et Task.Factory.StartNew sinon.


Si vous utilisez C # 5.0, vous devriez utiliser la await task; non bloquante await task; au lieu de task.Wait(); . (Voir la réponse de svick.)