<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Asynchronisme on Jérémie Litzler</title><link>https://jeremielitzler.fr/tags/asynchronisme/</link><description>Recent content in Asynchronisme on Jérémie Litzler</description><generator>Hugo -- gohugo.io</generator><language>fr</language><lastBuildDate>Mon, 12 Oct 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://jeremielitzler.fr/tags/asynchronisme/index.xml" rel="self" type="application/rss+xml"/><item><title>Usage du CancellationToken</title><link>https://jeremielitzler.fr/post/2026-10/usage-du-cancellation-token/</link><pubDate>Mon, 12 Oct 2026 00:00:00 +0000</pubDate><guid>https://jeremielitzler.fr/post/2026-10/usage-du-cancellation-token/</guid><description>&lt;img src="https://jeremielitzler.fr/images/2026-09-14-une-cassette-magnetique-deroulee.jpg" alt="Featured image of post Usage du CancellationToken" /&gt;&lt;p&gt;Quand passer le &lt;code&gt;CancellationToken&lt;/code&gt; à &lt;code&gt;Task.Run&lt;/code&gt; ?&lt;/p&gt;
&lt;p&gt;La réponse courte : toujours au code du délégué, et idéalement aussi à &lt;code&gt;Task.Run&lt;/code&gt;, mais ne croyez pas que ce second passage suffit à annuler le travail en cours.&lt;/p&gt;
&lt;p&gt;Voici pourquoi et comment bien l’utiliser.&lt;/p&gt;
&lt;h2 id="le-piège-du-cancellationtoken-dans-taskrun"&gt;Le piège du &lt;code&gt;CancellationToken&lt;/code&gt; dans &lt;code&gt;Task.Run&lt;/code&gt;
&lt;/h2&gt;&lt;p&gt;Le &lt;code&gt;CancellationToken&lt;/code&gt; passé à &lt;code&gt;Task.Run&lt;/code&gt; n’agit que sur la planification du délégué sur le &lt;code&gt;ThreadPool&lt;/code&gt; : si l’annulation est demandée avant que le délégué démarre (y compris pendant qu’il attend dans la file), il n’est pas exécuté et la tâche passe à l’état &lt;code&gt;Canceled&lt;/code&gt;. Une fois que le délégué s’exécute (ce qui se produit presque immédiatement), ce token n’interrompt plus rien.&lt;/p&gt;
&lt;p&gt;Beaucoup de développeurs écrivent ceci en pensant à tort que le délégué sera annulé :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ⚠️ INSUFFISANT - Le token n&amp;#39;interrompt PAS le délégué en cours d&amp;#39;exécution&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Ce code ignore le cancellationToken&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;DoSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="la-bonne-approche"&gt;La bonne approche
&lt;/h2&gt;&lt;p&gt;Passez d’abord le token au code à l’intérieur du délégué : c’est ce qui permet réellement d’interrompre le travail.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ✅ Le token est utilisé ICI, dans le code du délégué&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;DoSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Cela rend explicite qu’il revient au code du délégué d’honorer l’annulation de l’opération. L’annulation est coopérative : rien ne tue le délégué de l’extérieur.&lt;/p&gt;
&lt;p&gt;Passez ensuite le même token à &lt;code&gt;Task.Run&lt;/code&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ✅ Le token est honoré dans le délégué ET transmis à Task.Run&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;DoSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Ce second passage a deux effets utiles :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Si le token est déjà annulé avant le démarrage, le délégué n’est pas lancé.&lt;/li&gt;
&lt;li&gt;Si le délégué lève une &lt;code&gt;OperationCanceledException&lt;/code&gt; portant le même token, la tâche passe à &lt;code&gt;Canceled&lt;/code&gt;. Sans cela, le token ne correspond pas à celui de la tâche, qui passe à &lt;code&gt;Faulted&lt;/code&gt;. Un &lt;code&gt;await&lt;/code&gt; lève dans les deux cas une &lt;code&gt;OperationCanceledException&lt;/code&gt;, mais &lt;code&gt;IsCanceled&lt;/code&gt;, &lt;code&gt;IsFaulted&lt;/code&gt; et les continuations (&lt;code&gt;OnlyOnCanceled&lt;/code&gt;, etc.) se comportent différemment.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="les-trois-usages-du-cancellationtoken"&gt;Les trois usages du CancellationToken
&lt;/h2&gt;&lt;p&gt;Prenons l’exemple suivant :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CancellationTokenSource&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;DoSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ① Interrompt l&amp;#39;exécution&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ② Empêche le démarrage / fixe l&amp;#39;état Canceled&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ③ Annule l&amp;#39;attente (pas la tâche elle-même)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OperationCanceledException&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Gestion de l&amp;#39;annulation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Dans le délégué : c’est là que ça compte vraiment. Il arrête l’exécution de &lt;code&gt;DoSomething&lt;/code&gt;, à condition que la méthode soit écrite pour honorer les demandes d’annulation.&lt;/li&gt;
&lt;li&gt;Dans &lt;code&gt;Task.Run&lt;/code&gt; : il annule la tâche si le token est annulé AVANT que le délégué commence (ce qui est rare), et il permet à la tâche de se terminer à l’état &lt;code&gt;Canceled&lt;/code&gt; plutôt que &lt;code&gt;Faulted&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Dans &lt;code&gt;WaitAsync()&lt;/code&gt; (ou &lt;code&gt;Wait()&lt;/code&gt;) : il annule uniquement le processus d’attente de la tâche, sans réellement annuler la tâche elle-même.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="jli-notice jli-notice-note" id="Version de .NET" &gt;
&lt;p class="jli-notice-title"&gt;Version de .NET&lt;/p&gt;&lt;p&gt;&lt;code&gt;Task.WaitAsync(CancellationToken)&lt;/code&gt; n’existe que depuis .NET 6. Avec une version antérieure, utilisez &lt;code&gt;Task.WhenAny(task, Task.Delay(Timeout.Infinite, token))&lt;/code&gt; pour obtenir un effet comparable.&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;Attention si vous utilisez la version synchrone : &lt;code&gt;task.Wait()&lt;/code&gt; enveloppe l’annulation de la tâche dans une &lt;code&gt;AggregateException&lt;/code&gt; (contenant une &lt;code&gt;TaskCanceledException&lt;/code&gt;). Seule l’annulation de l’attente via &lt;code&gt;Wait(token)&lt;/code&gt; lève directement une &lt;code&gt;OperationCanceledException&lt;/code&gt;. Un &lt;code&gt;catch (OperationCanceledException)&lt;/code&gt; autour de &lt;code&gt;Wait()&lt;/code&gt; peut donc rater l’annulation. Préférez &lt;code&gt;await&lt;/code&gt;, qui extrait l’exception qu’on souhaite vraiment.&lt;/p&gt;
&lt;h2 id="comment-implémenter-lannulation-dans-votre-code"&gt;Comment implémenter l’annulation dans votre code
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;DoSomethingAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Vérifier périodiquement (utile surtout pour le travail CPU)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ThrowIfCancellationRequested&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Ou passer le token aux méthodes async&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="les-bonnes-pratiques"&gt;Les bonnes pratiques
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Passez toujours &lt;code&gt;CancellationToken&lt;/code&gt; aux méthodes asynchrones.&lt;/li&gt;
&lt;li&gt;Vérifiez l’annulation dans les opérations longues.&lt;/li&gt;
&lt;li&gt;Utilisez &lt;code&gt;ThrowIfCancellationRequested&lt;/code&gt; pour simplifier le code.&lt;/li&gt;
&lt;li&gt;Créez le &lt;code&gt;CancellationTokenSource&lt;/code&gt; là où se prend la décision d’annuler (interface, délai, requête HTTP) et ne transmettez que le &lt;code&gt;CancellationToken&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Disposez correctement de &lt;code&gt;CancellationTokenSource&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Pattern recommandé : le token vient de l&amp;#39;appelant, qui décide quand annuler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;DoWork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Côté appelant : annulation automatique après 5 secondes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CancellationTokenSource&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;cts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CancelAfter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="disposer-correctement-le-cancellationtokensource"&gt;Disposer correctement le &lt;code&gt;CancellationTokenSource&lt;/code&gt;
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;CancellationTokenSource&lt;/code&gt; implémente &lt;code&gt;IDisposable&lt;/code&gt; : il peut détenir un minuteur (après &lt;code&gt;CancelAfter&lt;/code&gt;) et des enregistrements auprès d’autres tokens (sources liées). Ne pas le disposer retarde leur libération.&lt;/p&gt;
&lt;h3 id="cas1"&gt;Cas 1
&lt;/h3&gt;&lt;p&gt;Une source locale, avec &lt;code&gt;using&lt;/code&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CancellationTokenSource&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;cts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CancelAfter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;DoSomethingAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// cts est disposé en sortant de la portée&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="cas2"&gt;Cas 2
&lt;/h3&gt;&lt;p&gt;Une source liée à un token parent, à disposer elle aussi, sinon son enregistrement auprès du parent subsiste :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;parentToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;linked&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CancellationTokenSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateLinkedTokenSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parentToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;linked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CancelAfter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;DoSomethingAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;linked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="cas3"&gt;Cas 3
&lt;/h3&gt;&lt;p&gt;Une source détenue par un objet de longue durée, qui devient &lt;code&gt;IDisposable&lt;/code&gt; à son tour :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IDisposable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;CancellationTokenSource&lt;/span&gt; &lt;span class="n"&gt;_cts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;StartAsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;DoWork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_cts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;_cts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_cts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cancel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Dispose&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_cts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cancel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// signale d&amp;#39;abord, au cas où une opération tourne encore&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_cts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dispose&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Ne disposez jamais la source tant que des opérations utilisent encore son token : demander &lt;code&gt;cts.Token&lt;/code&gt; après le &lt;code&gt;Dispose&lt;/code&gt; lève une &lt;code&gt;ObjectDisposedException&lt;/code&gt;. Annulez, attendez la fin des opérations, puis disposez.&lt;/p&gt;
&lt;div class="jli-notice jli-notice-tip" id="Suivez-moi !" &gt;
&lt;p class="jli-notice-title"&gt;Suivez-moi !&lt;/p&gt;&lt;p&gt;Merci d’avoir lu cet article. Assurez-vous de &lt;a href="https://x.com/LitzlerJeremie"&gt;me suivre sur X&lt;/a&gt;, de &lt;a href="https://iamjeremie.substack.com/"&gt;vous abonner à ma publication Substack&lt;/a&gt; et d’ajouter mon blog à vos favoris pour ne pas manquer les prochains articles.&lt;/p&gt;&lt;/div&gt;</description></item><item><title>Task.Run ou Task.Factory.StartNew</title><link>https://jeremielitzler.fr/post/2026-09/task-run-vs-task-startnew-dotnet/</link><pubDate>Mon, 14 Sep 2026 00:00:00 +0000</pubDate><guid>https://jeremielitzler.fr/post/2026-09/task-run-vs-task-startnew-dotnet/</guid><description>&lt;img src="https://jeremielitzler.fr/images/2026-09-14-une-cassette-magnetique-deroulee.jpg" alt="Featured image of post Task.Run ou Task.Factory.StartNew" /&gt;&lt;p&gt;&lt;code&gt;Task.Run&lt;/code&gt; est-il plus sûr, car il utilise le &lt;code&gt;TaskScheduler.Default&lt;/code&gt; alors que &lt;code&gt;Task.Factory.StartNew&lt;/code&gt; utilise &lt;code&gt;TaskScheduler.Current&lt;/code&gt; qui dépend du contexte ?&lt;/p&gt;
&lt;p&gt;C’est ce qu’on voit dans ce qui suit.&lt;/p&gt;
&lt;h2 id="différences-clés"&gt;Différences clés
&lt;/h2&gt;&lt;p&gt;Task.Run est effectivement plus sûr, car il utilise toujours &lt;code&gt;TaskScheduler.Default&lt;/code&gt; (c’est l’équivalent du &lt;code&gt;ThreadPool&lt;/code&gt;), tandis que &lt;code&gt;Task.Factory.StartNew&lt;/code&gt; utilise par défaut &lt;code&gt;TaskScheduler.Current&lt;/code&gt;, ce qui peut créer des comportements imprévisibles selon le contexte d’exécution.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Task.Run&lt;/code&gt; est essentiellement un raccourci qui appelle &lt;code&gt;Task.Factory.StartNew&lt;/code&gt; avec des paramètres par défaut sécurisés (cf. les sources de la documentation Microsoft en fin d’article), notamment :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TaskScheduler.Default&lt;/code&gt; (&lt;code&gt;ThreadPool&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TaskCreationOptions.DenyChildAttach&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CancellationToken.None&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;Task.Factory.StartNew&lt;/code&gt; offre plus de contrôle mais avec des risques si l’on ne maitrise pas assez bien son sujet :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Utilise par défaut &lt;code&gt;TaskScheduler.Current&lt;/code&gt; et non &lt;code&gt;TaskScheduler.Default&lt;/code&gt; (cf. Source InfoWorld)&lt;/li&gt;
&lt;li&gt;Ne comprend pas les délégués async (retourne &lt;code&gt;Task&amp;lt;Task&amp;gt;&lt;/code&gt; au lieu de &lt;code&gt;Task&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Nécessite &lt;code&gt;.Unwrap()&lt;/code&gt; pour les opérations asynchrones&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="quand-utiliser-lun-ou-lautre"&gt;Quand utiliser l’un ou l’autre
&lt;/h2&gt;&lt;p&gt;On utilise &lt;code&gt;Task.Run&lt;/code&gt; pour :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;La grande majorité des cas d’utilisation moderne&lt;/li&gt;
&lt;li&gt;Déléguer du travail &lt;em&gt;CPU-bound&lt;/em&gt; au &lt;code&gt;ThreadPool&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Travailler avec du code async/await&lt;/li&gt;
&lt;li&gt;Avoir des comportements prévisibles et sûrs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On utilise &lt;code&gt;Task.Factory.StartNew&lt;/code&gt; uniquement si :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On a besoin d’un &lt;code&gt;TaskScheduler&lt;/code&gt; personnalisé&lt;/li&gt;
&lt;li&gt;On doit spécifier qu’un processus sera occupé longtemps avec &lt;code&gt;TaskCreationOptions.LongRunning&lt;/code&gt; (cf. Source Programmer All)&lt;/li&gt;
&lt;li&gt;Vous devez passer un objet d’état pour optimiser les allocations mémoire (après profilage).&lt;/li&gt;
&lt;li&gt;Vous avez besoin de contrôler précisément les options de création de tâches&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="le-piège-du-taskschedulercurrent"&gt;Le piège du &lt;code&gt;TaskScheduler.Current&lt;/code&gt;
&lt;/h2&gt;&lt;p&gt;Le problème majeur est que &lt;code&gt;Task.Factory.StartNew&lt;/code&gt; examine d’abord le &lt;code&gt;TaskScheduler&lt;/code&gt; courant.&lt;/p&gt;
&lt;p&gt;Par exemple, si vous l’appelez depuis un gestionnaire d’événement UI (WinForms, WPF), la tâche s’exécutera sur le processus d’UI au lieu du &lt;code&gt;ThreadPool&lt;/code&gt;, causant potentiellement un blocage de l’interface. C’est le cas le plus connu !&lt;/p&gt;
&lt;p&gt;Dans mon cas, j’avais pris l’habitude d’utiliser &lt;code&gt;Task.Factory.StartNew&lt;/code&gt; , car je l’avais vu utiliser dans le code pour lancer un traitement en mode &lt;em&gt;Fire &amp;amp; Forget&lt;/em&gt;, ce qui n’est pas du tout recommandé.&lt;/p&gt;
&lt;p&gt;En effet, cela cache en général un souci de conception logicielle et une impréhension d’un traitement asynchrone.&lt;/p&gt;
&lt;p&gt;Par exemple, réaliser un envoi d’email avec un &lt;em&gt;Fire &amp;amp; Forget&lt;/em&gt; à la fin d’un paiement ne garantit pas l’envoi de l’email, même ce dernier ne « bloque » plus le retour de l’API de paiement. De plus, ce n’est pas la responsabilité du traitement de paiement d’envoyer l’email et vice-versa.&lt;/p&gt;
&lt;p&gt;La solution pour éviter le &lt;em&gt;Fire &amp;amp; Forget&lt;/em&gt; est un sujet très vaste qui tourne autour d’un choix d’architecture logicielle que je dois encore approfondir avec des cas concrets.&lt;/p&gt;
&lt;p&gt;A suivre donc…&lt;/p&gt;
&lt;h2 id="sources"&gt;Sources
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Blog .NET officiel—Task.Run vs Task.Factory.StartNew (Stephen Toub, 2011)&lt;/li&gt;
&lt;li&gt;StartNew is Dangerous (Stephen Cleary)&lt;/li&gt;
&lt;li&gt;InfoWorld—On Task.Factory.StartNew and Task.Run methods&lt;/li&gt;
&lt;li&gt;Code Maze—Difference Between Task.Run and Task.Factory.StartNew&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;La recommandation générale : préférez toujours Task.Run sauf si vous avez un besoin explicite qui nécessite des fonctionnalités avancées de StartNew.&lt;/p&gt;
&lt;div class="jli-notice jli-notice-tip" id="Suivez-moi !" &gt;
&lt;p class="jli-notice-title"&gt;Suivez-moi !&lt;/p&gt;&lt;p&gt;Merci d’avoir lu cet article. Assurez-vous de &lt;a href="https://x.com/LitzlerJeremie"&gt;me suivre sur X&lt;/a&gt;, de &lt;a href="https://iamjeremie.substack.com/"&gt;vous abonner à ma publication Substack&lt;/a&gt; et d’ajouter mon blog à vos favoris pour ne pas manquer les prochains articles.&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;Crédit : Photo de Paul Seling sur Pexels&lt;/p&gt;</description></item></channel></rss>