Derniers messages sur Zeste de Savoirhttps://zestedesavoir.com/forums/2021-12-22T14:06:09+01:00Les derniers messages parus sur le forum de Zeste de Savoir.Gestion des Threads en Go, message #2397592021-12-22T14:06:09+01:00nohar/@noharhttps://zestedesavoir.com/forums/sujet/15932/gestion-des-threads-en-go/?page=1#p239759<blockquote>
<p>ça m’a l’air en effet un petit peu plus compliqué que ma dernière solution</p>
</blockquote>
<p>Ça se fait plutôt bien avec la lib standard et la structure <code>sync.Pool</code> : </p>
<div class="hljs-code-div hljs-code-go"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span><span data-count="5"></span><span data-count="6"></span><span data-count="7"></span><span data-count="8"></span><span data-count="9"></span><span data-count="10"></span><span data-count="11"></span><span data-count="12"></span><span data-count="13"></span><span data-count="14"></span><span data-count="15"></span><span data-count="16"></span><span data-count="17"></span><span data-count="18"></span><span data-count="19"></span><span data-count="20"></span><span data-count="21"></span><span data-count="22"></span><span data-count="23"></span><span data-count="24"></span><span data-count="25"></span><span data-count="26"></span><span data-count="27"></span><span data-count="28"></span><span data-count="29"></span><span data-count="30"></span><span data-count="31"></span><span data-count="32"></span><span data-count="33"></span><span data-count="34"></span><span data-count="35"></span><span data-count="36"></span><span data-count="37"></span><span data-count="38"></span><span data-count="39"></span><span data-count="40"></span><span data-count="41"></span><span data-count="42"></span><span data-count="43"></span><span data-count="44"></span><span data-count="45"></span><span data-count="46"></span><span data-count="47"></span><span data-count="48"></span><span data-count="49"></span><span data-count="50"></span><span data-count="51"></span><span data-count="52"></span><span data-count="53"></span><span data-count="54"></span><span data-count="55"></span><span data-count="56"></span><span data-count="57"></span><span data-count="58"></span><span data-count="59"></span><span data-count="60"></span><span data-count="61"></span><span data-count="62"></span><span data-count="63"></span><span data-count="64"></span><span data-count="65"></span><span data-count="66"></span><span data-count="67"></span><span data-count="68"></span><span data-count="69"></span><span data-count="70"></span><span data-count="71"></span><span data-count="72"></span><span data-count="73"></span><span data-count="74"></span><span data-count="75"></span><span data-count="76"></span><span data-count="77"></span><span data-count="78"></span><span data-count="79"></span><span data-count="80"></span><span data-count="81"></span><span data-count="82"></span><span data-count="83"></span><span data-count="84"></span><span data-count="85"></span><span data-count="86"></span><span data-count="87"></span><span data-count="88"></span><span data-count="89"></span><span data-count="90"></span><span data-count="91"></span><span data-count="92"></span><span data-count="93"></span><span data-count="94"></span><span data-count="95"></span><span data-count="96"></span></div><pre><code class="hljs language-go"><span class="hljs-keyword">package</span> main
<span class="hljs-keyword">import</span> (
<span class="hljs-string">"fmt"</span>
<span class="hljs-string">"runtime"</span>
<span class="hljs-string">"sync"</span>
<span class="hljs-string">"time"</span>
)
<span class="hljs-comment">// Ici je simule des "handles"</span>
<span class="hljs-keyword">type</span> Handle <span class="hljs-keyword">int</span>
<span class="hljs-keyword">var</span> (
handle Handle
handleMtx sync.Mutex
)
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">newHandle</span><span class="hljs-params">()</span> <span class="hljs-title">Handle</span></span> {
time.Sleep(<span class="hljs-number">10</span> * time.Millisecond) <span class="hljs-comment">// obtenir un handle coûte 10ms</span>
handleMtx.Lock()
<span class="hljs-keyword">defer</span> handleMtx.Unlock()
handle++
<span class="hljs-keyword">return</span> handle
}
<span class="hljs-comment">// Ici l'implémentation du pool</span>
<span class="hljs-keyword">type</span> ClientFunc <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(Handle)</span> <span class="hljs-title">error</span></span>
<span class="hljs-keyword">type</span> ClientPool <span class="hljs-keyword">struct</span> {
sync.Pool
}
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">NewClientPool</span><span class="hljs-params">()</span> *<span class="hljs-title">ClientPool</span></span> {
c := &ClientPool{
Pool: sync.Pool{
New: <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span> <span class="hljs-title">interface</span></span>{} {
in := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> ClientFunc)
out := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> error)
<span class="hljs-keyword">go</span> runner(in, out)
<span class="hljs-keyword">return</span> &executor{in, out}
},
},
}
<span class="hljs-keyword">return</span> c
}
<span class="hljs-keyword">type</span> executor <span class="hljs-keyword">struct</span> {
In <span class="hljs-keyword">chan</span><- ClientFunc
Out <-<span class="hljs-keyword">chan</span> error
}
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">runner</span><span class="hljs-params">(in <-<span class="hljs-keyword">chan</span> ClientFunc, out <span class="hljs-keyword">chan</span><- error)</span></span> {
<span class="hljs-keyword">defer</span> <span class="hljs-built_in">close</span>(out)
runtime.LockOSThread()
<span class="hljs-keyword">defer</span> runtime.UnlockOSThread()
handle := newHandle()
<span class="hljs-keyword">for</span> f := <span class="hljs-keyword">range</span> in {
err := f(handle)
out <- err
}
}
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(c *ClientPool)</span> <span class="hljs-title">Run</span><span class="hljs-params">(f ClientFunc)</span> <span class="hljs-title">error</span></span> {
e := c.Get().(*executor)
e.In <- f
err, ok := <-e.Out
<span class="hljs-keyword">if</span> !ok || err != <span class="hljs-literal">nil</span> {
<span class="hljs-comment">// une erreur s'est produite, </span>
<span class="hljs-comment">// ou alors la goroutine a paniqué (ce qui a fermé e.Out)</span>
<span class="hljs-built_in">close</span>(e.In)
<span class="hljs-keyword">return</span> err
}
<span class="hljs-comment">// pas d'erreur, on peut retourner le runner au pool</span>
c.Put(e)
<span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
}
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
start := time.Now()
pool := NewClientPool()
<span class="hljs-keyword">var</span> wg sync.WaitGroup
wg.Add(<span class="hljs-number">100000</span>)
<span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i < <span class="hljs-number">100000</span>; i++ {
<span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {
<span class="hljs-keyword">defer</span> wg.Done()
pool.Run(<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(h Handle)</span> <span class="hljs-title">error</span></span> {
time.Sleep(time.Millisecond)
<span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
})
}()
}
wg.Wait()
fmt.Println(<span class="hljs-string">"elapsed: "</span>, time.Since(start))
fmt.Println(<span class="hljs-string">"allocated handles: "</span>, handle)
}
</code></pre></div>
<p>Ici, avec 100K goroutines qui vont taper sur le pool et bosser pendant 1ms chacune, ça me donne :</p>
<div class="hljs-code-div hljs-code-text"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span></div><pre><code class="hljs language-text">elapsed: 3.09040842s
allocated handles: 602
</code></pre></div>
<p>C’est sûrement un exemple un peu violent, mais l’intérêt du pool, c’est surtout de réutiliser facilement des ressources qui sont coûteuses à obtenir : ici on voit que même en stressant le pool en lui balançant 100K tâches d’un coup, il n’a créé que 600 (c’est variable en fait, ça oscille entre 400 et 800 chez moi) connexions/goroutines épinglées.</p>Gestion des Threads en Go, message #2397522021-12-22T08:39:40+01:00WinXaito/@WinXaitohttps://zestedesavoir.com/forums/sujet/15932/gestion-des-threads-en-go/?page=1#p239752<blockquote>
<p>Si jamais tu te retrouvais limité en perfs, tu pourrais avoir des solutions intermédiaires acceptables, comme maintenir un pool de goroutines qui sont chacune pinned à un thread (tu peux locker plusieurs OS threads comme ça, le runrime sait s’en accommoder), qui ont chacune leur handle, et qui sont responsables d’exécuter des appels/commandes qui viennent des autres goroutines de ton programme.</p>
</blockquote>
<p>Merci pour cette proposition.</p>
<p>ça m’a l’air en effet un petit peu plus compliqué que ma dernière solution, mais comme tu l’as dit, rien d’insurmontable.</p>
<p>Pour le moment, je pense partir sur la dernière solution imaginé, à savoir, la demande d’un handle à chaque appel (mais afin de gagner en performance, on maintient un handle durant toute la durée de vie de la lib).</p>
<p>En fait, la première demande prend du temps car la <code>DLL</code> Focas négocie la connexion TCP/IP avec la machine, mais, si une connexion est déjà ouverte, elle est réutilisé. Ce qui fait que les demande d’handle suivant sont très rapide.</p>
<p>Voici sur le schéma suivant la solution adopté.</p>
<figure><img src="/media/galleries/5697/778427ef-6ada-4d4e-804a-c3c0d3c35d06.png" alt="Demande des handles"><figcaption>Demande des handles</figcaption></figure>
<p>Rien ne m’empêchera d’utiliser une autre solution par la suite (c’est surtout la gestion interne de ma bibliothèque Focas qui changera, l’interface elle ne devrait pas trop bouger).</p>Gestion des Threads en Go, message #2397502021-12-22T02:32:46+01:00nohar/@noharhttps://zestedesavoir.com/forums/sujet/15932/gestion-des-threads-en-go/?page=1#p239750<p>Je ne suis pas sûr que chercher à manipuler explicitement les threads en Go soit une bonne idée. Ça me semble aller contre le langage. Du coup c’est plutôt vers la solution 1 que je me pencherais.</p>
<p>Si jamais tu te retrouvais limité en perfs, tu pourrais avoir des solutions intermédiaires acceptables, comme maintenir un pool de goroutines qui sont chacune <em>pinned</em> à un thread (tu peux locker plusieurs OS threads comme ça, le runrime sait s’en accommoder), qui ont chacune leur handle, et qui sont responsables d’exécuter des appels/commandes qui viennent des autres goroutines de ton programme.</p>
<p>Ça demanderait de créer un peu de logique pour abstraire la communication avec ces goroutines (au moyen de channels), mais rien d’insurmontable. Par exemple tu pourrais passer à la goroutine <em>pinned</em> une fonction (ou closure) qui prend un handle en argument, et la goroutine se contente de :</p>
<ul>
<li>Recevoir la fonction sur son chan d’entrée,</li>
<li>L’exécuter en lui passant son handle en argument,</li>
<li>Signaler sur son chan de sortie qu’elle a fini.</li>
</ul>
<p>En tout cas ça ne me semble pas "sale" comme solution, c’est le problème qui est sale, mais cette façon d’y répondre me semble idiomatique.</p>Gestion des Threads en Go, message #2397482021-12-21T23:30:43+01:00ache/@achehttps://zestedesavoir.com/forums/sujet/15932/gestion-des-threads-en-go/?page=1#p239748<figure><blockquote>
<p>Il n’est pas possible de gérer des Thread directement en Go (du moins pas à ma connaissance). Et j’ai besoin de garder l’avantage goroutines/channels.</p>
</blockquote><figcaption><a href="https://zestedesavoir.com/forums/sujet/15932/gestion-des-threads-en-go/?page=1#p239743">WinXaito</a></figcaption></figure>
<p><img src="/static/smileys/svg/blink.svg" alt="O_o" class="smiley"> ! Désolé ! Je ne savais pas. Du coup Go ne permet pas une gestion fine des fils d’exécution. C’est curieux.</p>Gestion des Threads en Go, message #2397472021-12-21T23:13:31+01:00Fantasio/@Fantasiohttps://zestedesavoir.com/forums/sujet/15932/gestion-des-threads-en-go/?page=1#p239747<p>Hello,</p>
<p>Je te rejoins sur l’analyse et la solution du problème. La librarie utilise très certainement du thread local storage, et comme les goroutines peuvent être schédulées sur n’importe quel thread, ça pète la lib si tu appelles depuis un autre thread. Donc si tu pin la goroutine à un thread tu corriges le problème.</p>
<p>Ça m’a l’air d’être une solution propre et adaptée <img src="/static/smileys/svg/smile.svg" alt=":)" class="smiley"> </p>Gestion des Threads en Go, message #2397432021-12-21T21:29:19+01:00WinXaito/@WinXaitohttps://zestedesavoir.com/forums/sujet/15932/gestion-des-threads-en-go/?page=1#p239743<figure><blockquote>
<p>Je ne voyais pas les Goroutines comme des Threads. Si tu veux faire des threads, pourquoi ne pas utiliser de vrai threads ? Comme ça tu peux applique ta solution 2, non ?</p>
</blockquote><figcaption><a href="https://zestedesavoir.com/forums/sujet/15932/gestion-des-threads-en-go/?page=1#p239742">ache</a></figcaption></figure>
<p>Il n’est pas possible de gérer des Thread directement en Go (du moins pas à ma connaissance). Et j’ai besoin de garder l’avantage goroutines/channels.</p>Gestion des Threads en Go, message #2397422021-12-21T19:44:11+01:00ache/@achehttps://zestedesavoir.com/forums/sujet/15932/gestion-des-threads-en-go/?page=1#p239742<p>Je ne voyais pas les Goroutines comme des Threads. Si tu veux faire des threads, pourquoi ne pas utiliser de vrai threads ? Comme ça tu peux applique ta solution 2, non ?</p>Gestion des Threads en Go, message #2397402021-12-21T17:56:04+01:00WinXaito/@WinXaitohttps://zestedesavoir.com/forums/sujet/15932/gestion-des-threads-en-go/?page=1#p239740<p>Bonjour à tous,</p>
<p>Je fais aujourd’hui face à la gestion des Threads en Go, qui m’apporte quelques mésaventures, notamment dues au fait qu’on ne sait pas vraiment ce qu’il se cache là derrière.</p>
<p>Pour les besoins de mon projet, je dois faire des interactions avec des machines à commande numérique (CNC) au travers du protocole Focas. (Il s’agit d’un protocole de communication développé par Fanuc, qui développe des commandes numériques pour les machines)</p>
<p>Pour celles et ceux qui ne sauraient pas, voici de quoi je parle:</p>
<div class="custom-block custom-block-spoiler"><div class="custom-block-body"><figure><img src="https://www.fanuc.eu/~/media/corporate/customer-cases/mag/mag-400x400.jpg" alt="Commande numérique Fanuc"><figcaption>Commande numérique Fanuc</figcaption></figure></div></div>
<p>J’ai à ma disposition une <code>DLL</code> (Fwlib) me permettant d’interagir avec ces commandes numériques, dont on retrouve la documentation <a href="https://www.inventcom.net/fanuc-focas-library/general/fwlib32">ici</a>.</p>
<p>Dans mon projet en Go, j’interagis ainsi avec cette DLL.</p>
<hr>
<p>Tout se passait bien, jusqu’au moment où … je commence à travailler avec les Goroutines, à ce moment-là, plus rien n’a fonctionné. Je me dis que la librairie ne supporte pas les accès concurrents, ce qui ne me poserait pas de problème. </p>
<p>Je me mis donc à mettre des lock (mutex) sur toutes les opérations faisant appel à la DLL. Et la, au moment de Run mon programme, toujours le même problème !<br>
Je me dis que c’est des problèmes de temporisation, qu’il faut un peu calmer le jeu, je rajoute donc quelques <code>sleep</code>.</p>
<p>Et bien, toujours pas ! Quand ça ne veut pas, ça ne veut pas. Du coup, je retire mes <code>Goroutine</code> tout en laissant les <code>sleeps</code>, et la, stupeur, ça fonctionne <strong>parfois</strong>.</p>
<p>Me disant que c’est une bibliothèque très mal faite, je vais tout de même faire un essai en <code>C#</code> pour voir ce que ça donne et étrangement, ça fonctionne (uniquement les <code>sleep</code>, pas les tâches asynchrones).</p>
<hr>
<p><strong>Recherche d’informations dans la documentation du protocole</strong></p>
<blockquote>
<p>Once the library handle number is acquired, it must be held until the application program terminates, because it is necessary to pass the number as an argument to each CNC/PMC Data window library function.</p>
<p><strong>The library handle is owned by the thread that got it. Even if the thread-A which has already got a library handle shows the library handle to another thread-B, the thread-B cannot use that library handle.</strong></p>
</blockquote>
<p>Je tiens enfin une piste ! C’est donc de là que viens le problème avec les tâches exécutées en parallèle.</p>
<p>Je comprends aussi rapidement que le problème avec les <code>sleep</code> viens du fait que le <code>runtime Go</code> peut changer de Thread à tout moment. Pour confirmer cela, j’ai fait appel à la méthode <code>runtime.LockOSThread()</code>, qui permet de bloquer l’exécution en cours sur le même Thread jusqu’à l’appel de <code>runtime.UnlockOSThread()</code>. Et effectivement, ça fonctionne !</p>
<p>Sur le code suivant, qui ne fonctionnait pas, fonctionne après l’ajout de <code>runtime.LockOSThread</code>. (Précision: <code>focas.Channel()</code> est une méthode que j’ai implémentée qui va faire un appel avec l'<code>handle</code> à la DLL).</p>
<div class="hljs-code-div hljs-code-go"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span><span data-count="5"></span><span data-count="6"></span><span data-count="7"></span><span data-count="8"></span><span data-count="9"></span><span data-count="10"></span></div><pre><code class="hljs language-go">runtime.LockOSThread()
<span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i < <span class="hljs-number">200</span>; i++ {
_, e := focas.Channel()
<span class="hljs-keyword">if</span> e != <span class="hljs-literal">nil</span> {
log.Fatalln(i, e)
}
time.Sleep(time.Millisecond * <span class="hljs-number">10</span>)
}
runtime.UnlockOSThread()
</code></pre></div>
<hr>
<p>Comme vous le devinez surement, on en arrive enfin à mon problème.</p>
<ul>
<li>Ma première idée pour résoudre ce problème est de demander un <code>handle</code> à chaque appel à une méthode, le problème ? La demande d’un <code>handle</code> prend du temps (~250ms), le temps d’initialiser la connexion TCP/IP à la machine CNC.</li>
<li>Mon idée suivante, c’est de récupérer l’ID du Thread en cours, et de vérifier dans un <code>map</code> si un <code>handle</code> a déjà été généré pour ce Thread, si ce n’est pas le cas on en génère un, sinon on utilise l’existant.</li>
</ul>
<p>La deuxième idée me paraît être idéale, mais un petit problème se pose. Il n’est pas possible en Go de savoir sur quel Thread l’exécution se fait !
Selon <a href="https://github.com/golang/go/issues/18590">l’issue suivante</a>, les développeurs du langage Go ne souhaitent pas rendre cela accessible, pour éviter que les développeurs en fassent n’importe quoi.</p>
<p>Finalement, ma dernière idée est d’ouvrir un <code>handle</code> au démarrage dans une Goroutine, locké à son Thread. Ensuite à chaque appel à la DLL, je fais la demande d’un nouvel <code>handle</code> que je libère ensuite.</p>
<p>Et le résultat est sans appel. Si j’ouvre un <code>handle</code> que je maintiens, 100 exécutions de ma méthode me prennent <code>150ms</code>, si j’enlève le <code>handle</code> maintenu, l’exécution passe à 22s ! L’exécution prend environ 150x plus de temps.</p>
<p>Vous trouverez ici le code source de mon essai. <a href="https://gist.github.com/WinXaito/c4eba0e808c8587dbdbd2a2687260bd5">https://gist.github.com/WinXaito/c4eba0e808c8587dbdbd2a2687260bd5</a> (Pour passer de 150ms à 22s, j’ai simplement commenter les lignes 38 et 39)</p>
<hr>
<p>Et finalement mes questions,</p>
<div class="custom-block custom-block-question"><div class="custom-block-body"><p>Concernant la dernière solution, qui semble fonctionner, je ne sais pas si elle est idéale. Qu’en pensez-vous ?</p></div></div>
<div class="custom-block custom-block-question"><div class="custom-block-body"><p>Concernant la deuxième proposition (récupérer un ID sur le Thread et maintenir une correspondance ID<->Handle), savez-vous si c’est faisable (malgré mes trouvailles je n’ai peut-être pas cherché assez loin) et surtout, est-ce que même si ça avait été possible, est-ce que ça aurait été une bonne idée ?</p></div></div>
<div class="custom-block custom-block-question"><div class="custom-block-body"><p>Auriez-vous peut-être d’autres idées plus idéales à me proposer ?</p></div></div>
<hr>
<p>Je vous remercie, et vous souhaite d’avance de belles fêtes de fin d’années à toutes et tous !</p>[Python] Multiplexage avec le module select, message #2161112020-02-23T03:24:33+01:00buffalo974/@buffalo974https://zestedesavoir.com/forums/sujet/13640/python-multiplexage-avec-le-module-select/?page=1#p216111<p>merci !</p>[Python] Multiplexage avec le module select, message #2159822020-02-20T09:37:25+01:00entwanne/@entwannehttps://zestedesavoir.com/forums/sujet/13640/python-multiplexage-avec-le-module-select/?page=1#p215982<figure><blockquote>
<p>Pour utiliser un chaque cœur d’un processeur multi-cœur, il faut soit lancer plusieurs programmes au niveau du système d’exploitation, soit <strong>lancer plusieurs threads au niveau d’un même programme</strong>.</p>
</blockquote><figcaption><a href="https://zestedesavoir.com/forums/sujet/13640/python-multiplexage-avec-le-module-select/?page=1#p215980">r0anne</a></figcaption></figure>
<p>À relativiser cependant en Python, puisqu’actuellement avec le <em><abbr title="Global Interpreter Lock">GIL</abbr></em> même si deux <em>threads</em> s’exécutent sur deux cœurs différents, ils ne le feront jamais simultanément.</p>[Python] Multiplexage avec le module select, message #2159802020-02-20T08:51:44+01:00r0anne/@r0annehttps://zestedesavoir.com/forums/sujet/13640/python-multiplexage-avec-le-module-select/?page=1#p215980<p>Salut,</p>
<p>À l’origine, il y a longtemps, les microprocesseurs disposaient d’un seul cœur, donc d’un seul « fil d’exécution » : un seul thread au niveau matériel. Les instructions étaient exécutées les unes après les autres :</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span><span></span></div><pre><code class="hljs language-coq">| <span class="hljs-type">Instruction</span> <span class="hljs-number">1</span> | <span class="hljs-type">Instruction</span> <span class="hljs-number">2</span> | <span class="hljs-type">Instruction</span> <span class="hljs-number">3</span> | <span class="hljs-type">... |
======> Temps</span> ======>
</code></pre></div>
<p>Par la suite, et pour monter en performances plus facilement qu’en miniaturisant et rendant toujours plus puissants les microprocesseurs, on a décidé de mettre plusieurs microprocesseurs logiques les uns à côté des autres : c’est l’avènement du « multi-cœur ».</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span><span></span><span></span><span></span></div><pre><code class="hljs language-gherkin"> /\
Cœurs ||<span class="hljs-string"> </span>|<span class="hljs-string"> Instruction 1 </span>|<span class="hljs-string"> Instruction 2 </span>|<span class="hljs-string"> Instruction 3 </span>|<span class="hljs-string"> ... </span>|
||<span class="hljs-string"> </span>|<span class="hljs-string"> Instruction 4 </span>|<span class="hljs-string"> Instruction 5 </span>|<span class="hljs-string"> Instruction 6 </span>|<span class="hljs-string"> ... </span>|
======> Temps ======>
</code></pre></div>
<p>Pour utiliser un chaque cœur d’un processeur multi-cœur, il faut soit lancer plusieurs programmes au niveau du système d’exploitation, soit <strong>lancer plusieurs threads au niveau d’un même programme</strong>.</p>
<p>Maintenant, imaginons que je veuille que mon programme écoute sur 10 sockets différentes. Logiquement, écouter sur un socket va bloquer mon programme, ou du moins 10 threads.</p>
<p>Si j’exécute plusieurs programmes et que mon système d’exploitation est multi-tâches, alors il va mutualiser le fil d’exécution du CPU entre différents programmes (si j’ai plus de programmes en exécution que de cœurs) :</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span><span></span></div><pre><code class="hljs language-coq">| <span class="hljs-type">Instruction</span> <span class="hljs-number">1</span> programme A | <span class="hljs-type">Instruction</span> <span class="hljs-number">1</span> programme B | <span class="hljs-type">Instruction</span> <span class="hljs-number">2</span> programme A | <span class="hljs-type">... |
======> Temps</span> ======>
</code></pre></div>
<p>Il en est de même si j’ai différents threads (et que j’ai plus de threads en activité que de cœurs) :</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span><span></span></div><pre><code class="hljs language-coq">| <span class="hljs-type">Instruction</span> <span class="hljs-number">1</span> thread A | <span class="hljs-type">Instruction</span> <span class="hljs-number">1</span> thread B | <span class="hljs-type">Instruction</span> <span class="hljs-number">2</span> thread B | <span class="hljs-type">... |
======> Temps</span> ======>
</code></pre></div>
<p>Maintenant, utiliser des threads a des inconvénients :</p>
<ul>
<li>
<p>Tu peux faire communiquer des threads entre eux, mais c’est compliqué. Ils risquent de se marcher sur les pieds : que se passe-t-il si l’un s’apprête à modifier deux variables liées entre elles à la suite, commence à en modifier une, mais que le second thread lit les deux variables sans que la deuxième variable n’ait encore été modifiée, et qu’il obtient des résultats contradictoires en conséquence ? La programmation avec les threads est plein de bugs tordus comme ça.<br>
<br>
Pour les éviter, il faut « bloquer » explicitement des zones du code qui touchent une même variable pour éviter qu’elles ne soient exécutées par deux programmes à la fois, c’est compliqué et ça créé des sacrés sacs de nœuds.<br>
</p>
</li>
<li>
<p>Les threads représentent un léger coût en performance et en mémoire. Il faut que le système les réveillent, les endorment, les réveillent… avec toutes les variables et le contexte qui vont avec à chaque fois. C’est pour ça que les serveurs qui sont utilisés pour de fortes nécessités de performances, comme Nginx, évitent d’utiliser des threads.</p>
</li>
</ul>
<p>Maintenant, quelle est l’alternative aux threads ? Les <strong>boucles événementielles</strong>. Le principe est simple : le programme se met d’accord avec le noyau pour écouter sur plusieurs sockets (ou plusieurs sockets + une entrée de terminal + un périphérique spécial, etc.) à la fois, et se faire réveiller par le noyau uniquement quand il y a de nouvelles données / un nouvel évènement à traiter.</p>
<p>Ainsi, il n’a <strong>qu’un seul fil d’exécution</strong> et qu’un seul état (et n’utilise qu’un seul cœur, sauf si tu commences à mettre une boucle événementielle sur chaque thread…).</p>
<p>Le module <code>select</code> permet d’utiliser une des API bas-niveau qui sont exposées par le noyau pour permettre des boucles événementielles sur plusieurs descripteurs (sockets, fichiers…), l’API <code>select</code>, disponible sur pratiquement toutes les plateformes. L’idée est donc que tu lui passes plusieurs sockets et que ton programme se fasse réveiller au bon moment. D’autres API plus récentes s’appellent <code>poll</code>, <code>epoll</code> (sous Linux) ou <code>kqueue</code> (sous FreeBSD), mais elles sont d’abord utilisées en C et ne sont pas disponibles sous toutes les plateformes.</p>
<p><code>asyncio</code> est une surcouche par-dessus ces différentes API qui te permettra d’utiliser ce qu’on appelle des <strong>coroutines</strong> : des fonctions qui te permettront d’avoir un programme avec un seul fil d’exécution et un seul état, mais chaque fonction s’endormira individuellement et repassera la main à la boucle évènementielle quand tu auras un appel bloquant (lecture, écriture… sur par exemple un socket) à faire. Ces appels sont préfixés par le mot-clef <code>await</code> dans les versions récentes Python, et les définitions de coroutines sont préfixées par le mot-clef <code>async</code>.</p>
<p>Les coroutines sont une des différentes approches pour faire ce qu’on appelle de l’asynchrone (intégrer proprement une boucle événementielle à ton programme). Une autre approche est celle des callbacks, utilisée par Node.JS (une autre fonction, en général imbriquée dans la première, sera appelée « à retardement » quand la boucle évènementielle aura retourné quelque chose). Il y a aussi des bibliothèques qui t’encouragent à faire des callbacks en Python, mais c’est moins fréquent.</p>
<p>Dans tous les cas, le module <code>select</code> est peu utilisé car c’est principalement une « brique » qui te permet d’accéder à une API bas-niveau, pour des besoins bas-niveau.</p>
<p>Bonne journée,</p>[Python] Multiplexage avec le module select, message #2159422020-02-19T21:52:30+01:00entwanne/@entwannehttps://zestedesavoir.com/forums/sujet/13640/python-multiplexage-avec-le-module-select/?page=1#p215942<p>C’est juste une technique différente.
Ça permet d’avoir des appels qui ne bloquent pas le <em>thread</em> courant et ça peut être utile quand on ne veut justement aps instacier de nouveaux <em>threads</em> et avoir à les gérer.</p>
<p>Par ailleurs, note que le module <a href="https://docs.python.org/3/library/selectors.html"><code>selectors</code></a> fournit une interface plus haut-niveau de <em>multiplexing</em>.
La page de documentation comporte aussi des exemples.</p>[Python] Multiplexage avec le module select, message #2159382020-02-19T21:18:43+01:00buffalo974/@buffalo974https://zestedesavoir.com/forums/sujet/13640/python-multiplexage-avec-le-module-select/?page=1#p215938<p>salut, qu’apporte le multiplexing avec le module select par rapport aux threads ?
auriez vous des exemples faciles à comprendre ?</p>Erreur Thread [VB.NET], message #1875472018-08-29T12:50:23+02:00LeGeek57510/@LeGeek57510https://zestedesavoir.com/forums/sujet/11207/erreur-thread-vbnet/?page=2#p187547<p>Très bien,</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div><pre><code class="hljs language-vbnet"><span class="hljs-keyword">Private</span> <span class="hljs-keyword">Sub</span> Button1_Click(<span class="hljs-keyword">ByVal</span> sender <span class="hljs-keyword">As</span> System.<span class="hljs-built_in">Object</span>, <span class="hljs-keyword">ByVal</span> e <span class="hljs-keyword">As</span> System.EventArgs) <span class="hljs-keyword">Handles</span> Button1.Click
<span class="hljs-keyword">If</span> <span class="hljs-keyword">Not</span> TextBox1.<span class="hljs-keyword">Text</span> = <span class="hljs-string">""</span> <span class="hljs-keyword">Then</span>
<span class="hljs-keyword">If</span> <span class="hljs-keyword">Not</span> TextBox2.<span class="hljs-keyword">Text</span> = <span class="hljs-string">""</span> <span class="hljs-keyword">Then</span>
<span class="hljs-keyword">If</span> <span class="hljs-keyword">Not</span> TextBox3.<span class="hljs-keyword">Text</span> = <span class="hljs-string">""</span> <span class="hljs-keyword">Then</span>
<span class="hljs-keyword">If</span> <span class="hljs-keyword">Not</span> TextBox5.<span class="hljs-keyword">Text</span> = <span class="hljs-string">""</span> <span class="hljs-keyword">Then</span>
<span class="hljs-keyword">If</span> <span class="hljs-keyword">Not</span> ComboBox1.<span class="hljs-keyword">Text</span> = <span class="hljs-string">""</span> <span class="hljs-keyword">Then</span>
<span class="hljs-keyword">If</span> CheckBox1.Checked = <span class="hljs-literal">True</span> <span class="hljs-keyword">Then</span>
<span class="hljs-keyword">If</span> CheckBox3.Checked = <span class="hljs-literal">True</span> <span class="hljs-keyword">Then</span>
<span class="hljs-keyword">Dim</span> Thread1Start <span class="hljs-keyword">As</span> <span class="hljs-keyword">New</span> ThreadStart(<span class="hljs-keyword">AddressOf</span> sendMail)
<span class="hljs-keyword">Dim</span> Thread1 <span class="hljs-keyword">As</span> <span class="hljs-keyword">New</span> Thread(Thread1Start)
Thread1.IsBackground = <span class="hljs-literal">True</span>
Thread1.Start()
<span class="hljs-keyword">End</span> <span class="hljs-keyword">If</span>
<span class="hljs-keyword">End</span> <span class="hljs-keyword">If</span>
<span class="hljs-keyword">Else</span>
errChamp()
<span class="hljs-keyword">End</span> <span class="hljs-keyword">If</span>
<span class="hljs-keyword">Else</span>
errChamp()
<span class="hljs-keyword">End</span> <span class="hljs-keyword">If</span>
<span class="hljs-keyword">Else</span>
errChamp()
<span class="hljs-keyword">End</span> <span class="hljs-keyword">If</span>
<span class="hljs-keyword">Else</span>
errChamp()
<span class="hljs-keyword">End</span> <span class="hljs-keyword">If</span>
<span class="hljs-keyword">Else</span>
errChamp()
<span class="hljs-keyword">End</span> <span class="hljs-keyword">If</span>
<span class="hljs-keyword">End</span> <span class="hljs-keyword">Sub</span>
</code></pre></div>
<p>Voilà, c’était pour le bouton et le reste:</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div><pre><code class="hljs language-vbnet"><span class="hljs-keyword">Sub</span> errChamp()
MessageBox.Show(<span class="hljs-string">"Erreur, tout les champs ne sont pas complétés"</span>, <span class="hljs-string">"Erreur"</span>, MessageBoxButtons.OK, MessageBoxIcon.<span class="hljs-keyword">Error</span>)
<span class="hljs-keyword">End</span> <span class="hljs-keyword">Sub</span>
<span class="hljs-keyword">Sub</span> sendMail()
Invoke(<span class="hljs-keyword">New</span> MethodInvoker(<span class="hljs-keyword">Sub</span>()
<span class="hljs-keyword">While</span> My.Settings.mailSend = <span class="hljs-number">0</span>
<span class="hljs-keyword">Try</span>
<span class="hljs-keyword">Dim</span> mail <span class="hljs-keyword">As</span> <span class="hljs-keyword">New</span> MailMessage
<span class="hljs-keyword">Dim</span> SMTP <span class="hljs-keyword">As</span> <span class="hljs-keyword">New</span> SmtpClient
<span class="hljs-keyword">If</span> ComboBox1.SelectedItem = ComboBox1.Items(<span class="hljs-number">0</span>) <span class="hljs-keyword">Then</span>
SMTP = <span class="hljs-keyword">New</span> SmtpClient(<span class="hljs-string">"smtp.gmail.com"</span>)
SMTP.Port = <span class="hljs-string">"587"</span>
<span class="hljs-keyword">End</span> <span class="hljs-keyword">If</span>
mail.<span class="hljs-keyword">From</span> = <span class="hljs-keyword">New</span> MailAddress(TextBox1.<span class="hljs-keyword">Text</span>) <span class="hljs-comment">' De</span>
mail.<span class="hljs-keyword">To</span>.Add(TextBox3.<span class="hljs-keyword">Text</span>) <span class="hljs-comment">' Pour</span>
mail.Subject = TextBox5.<span class="hljs-keyword">Text</span>
mail.Body = RichTextBox1.<span class="hljs-keyword">Text</span>
<span class="hljs-keyword">If</span> <span class="hljs-keyword">Not</span> TextBox7.<span class="hljs-keyword">Text</span> = <span class="hljs-string">""</span> <span class="hljs-keyword">Then</span>
<span class="hljs-keyword">Try</span>
<span class="hljs-keyword">Dim</span> mailAtt = <span class="hljs-keyword">New</span> Net.Mail.Attachment(TextBox7.<span class="hljs-keyword">Text</span>)
mail.Attachments.Add(mailAtt)
<span class="hljs-keyword">Catch</span> ex <span class="hljs-keyword">As</span> Exception
MessageBox.Show(<span class="hljs-string">"Erreur, "</span> & ex.ToString, <span class="hljs-string">"Erreur"</span>, MessageBoxButtons.OK, MessageBoxIcon.<span class="hljs-keyword">Error</span>)
<span class="hljs-keyword">End</span> <span class="hljs-keyword">Try</span>
<span class="hljs-keyword">End</span> <span class="hljs-keyword">If</span>
SMTP.Credentials = <span class="hljs-keyword">New</span> System.Net.NetworkCredential(TextBox1.<span class="hljs-keyword">Text</span>, TextBox2.<span class="hljs-keyword">Text</span>)
SMTP.EnableSsl = <span class="hljs-literal">True</span>
SMTP.Send(mail)
My.Settings.mailSend = <span class="hljs-number">1</span>
My.Settings.Save()
<span class="hljs-keyword">if</span> My.Settings.mailSend = <span class="hljs-number">1</span> <span class="hljs-keyword">Then</span>
MsgBox(<span class="hljs-string">"Mail envoyer !"</span>)
<span class="hljs-keyword">End</span> <span class="hljs-keyword">If</span>
<span class="hljs-keyword">Me</span>.Refresh()
<span class="hljs-keyword">Catch</span> ex <span class="hljs-keyword">As</span> Exception
MessageBox.Show(<span class="hljs-string">"Erreur, "</span> & ex.ToString, <span class="hljs-string">"Erreur"</span>, MessageBoxButtons.OK, MessageBoxIcon.<span class="hljs-keyword">Error</span>)
<span class="hljs-keyword">End</span> <span class="hljs-keyword">Try</span>
<span class="hljs-keyword">End</span> <span class="hljs-keyword">While</span>
<span class="hljs-keyword">End</span> <span class="hljs-keyword">Sub</span>))
<span class="hljs-keyword">End</span> <span class="hljs-keyword">Sub</span>
</code></pre></div>Erreur Thread [VB.NET], message #1875412018-08-29T12:32:21+02:00anonyme/@anonymehttps://zestedesavoir.com/forums/sujet/11207/erreur-thread-vbnet/?page=2#p187541<p>Si tu postais ton code en entier ça nous aiderais beaucoup pour t’aider.</p>Erreur Thread [VB.NET], message #1875032018-08-28T23:47:53+02:00LeGeek57510/@LeGeek57510https://zestedesavoir.com/forums/sujet/11207/erreur-thread-vbnet/?page=2#p187503<figure><blockquote>
<p>Bonjour LeGeek57510,</p>
<p>Je te saurais gré de ne pas publier inutilement dans ton propre sujet. Pour rappel : d’une part c’est un forum et non une salle de <em>chat</em>, les réponses ne sont pas immédiates et, d’autre part, si tu n’as pas de réponses c’est probablement parce que personne n’a de solution pour l’instant, inutile de relancer toute les heures ou demi-heures.</p>
</blockquote><figcaption><a href="https://zestedesavoir.com/forums/sujet/11207/erreur-thread-vbnet/?page=2#p187484">Taurre</a></figcaption></figure>
<p>Très bien, de toute façon je m’en doutait un peu, trop complexe mon problème <img src="/static/smileys/rire.gif" alt=":lol:" class="smiley"><img src="/static/smileys/rire.gif" alt=":lol:" class="smiley">Je vais attendre une réponse venant de la part d’une personne qui aurais éventuellement un bout de chemin menant à la victoire !
Merci</p>Erreur Thread [VB.NET], message #1874842018-08-28T20:59:22+02:00Taurre/@Taurrehttps://zestedesavoir.com/forums/sujet/11207/erreur-thread-vbnet/?page=2#p187484<p>Bonjour LeGeek57510,</p>
<p>Je te saurais gré de ne pas publier inutilement dans ton propre sujet. Pour rappel : d’une part c’est un forum et non une salle de <em>chat</em>, les réponses ne sont pas immédiates et, d’autre part, si tu n’as pas de réponses c’est probablement parce que personne n’a de solution pour l’instant, inutile de relancer toute les heures ou demi-heures.</p>Erreur Thread [VB.NET], message #1874802018-08-28T20:21:54+02:00LeGeek57510/@LeGeek57510https://zestedesavoir.com/forums/sujet/11207/erreur-thread-vbnet/?page=2#p187480<p><strong>UP</strong></p>Erreur Thread [VB.NET], message #1874772018-08-28T19:26:14+02:00LeGeek57510/@LeGeek57510https://zestedesavoir.com/forums/sujet/11207/erreur-thread-vbnet/?page=1#p187477<p>Double UP</p>Erreur Thread [VB.NET], message #1874762018-08-28T19:05:42+02:00LeGeek57510/@LeGeek57510https://zestedesavoir.com/forums/sujet/11207/erreur-thread-vbnet/?page=1#p187476<p>Up</p>Erreur Thread [VB.NET], message #1874182018-08-28T02:19:09+02:00LeGeek57510/@LeGeek57510https://zestedesavoir.com/forums/sujet/11207/erreur-thread-vbnet/?page=1#p187418<p>Personne n’a d’idée ? Merci</p>