<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Gil on sharefun&#39;s blog</title>
        <link>https://sharefun.dev/tags/gil/</link>
        <description>Recent content in Gil on sharefun&#39;s blog</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-TW</language>
        <copyright>Hsueh-Fang Yeh</copyright>
        <lastBuildDate>Fri, 22 Apr 2022 00:00:00 +0000</lastBuildDate><atom:link href="https://sharefun.dev/tags/gil/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>A Minimal Example of Concurrent Python</title>
            <link>https://sharefun.dev/posts/a-minimal-example-of-concurrent-python/</link>
            <pubDate>Fri, 22 Apr 2022 00:00:00 +0000</pubDate>
            <guid>https://sharefun.dev/posts/a-minimal-example-of-concurrent-python/</guid>
            <description>&lt;p&gt;The CPython interpreter usese &lt;a class=&#34;link&#34; href=&#34;https://wiki.python.org/moin/GlobalInterpreterLock&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;GIL&lt;/a&gt; (global interpreter lock), to prevent threads from executing Python bytecodes at once.&lt;/p&gt;&#xA;&lt;p&gt;Suppose I have two components who need to be run in parallel in a modern multi-core processor. Say, &lt;code&gt;add&lt;/code&gt; and &lt;code&gt;mul&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;add&lt;/span&gt;(n: int) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; int:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(n):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        result &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; (i &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; result&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mul&lt;/span&gt;(n: int) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;None&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Run many times to get longer execution period&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(&lt;span style=&#34;color:#ae81ff&#34;&gt;4000000&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(n):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            result &lt;span style=&#34;color:#f92672&#34;&gt;*=&lt;/span&gt; (i &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; result&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Impose that these two tiny components have to be run sequentially, &lt;code&gt;mul&lt;/code&gt; receives &lt;code&gt;add&lt;/code&gt;&amp;rsquo;s output.&lt;/p&gt;&#xA;&lt;pre class=&#34;mermaid&#34; style=&#34;visibility:hidden&#34;&gt;sequenceDiagram&#xA;    participant main&#xA;    participant mul&#xA;    participant add&#xA;    main-&gt;&gt;mul: For every stdin&#xA;    activate main&#xA;    mul-&gt;&gt;add: result&#xA;    add-&gt;&gt;mul: &#xA;    mul-&gt;&gt;main: &#xA;    deactivate main&lt;/pre&gt;&lt;p&gt;Run it twice and fix the input of &lt;code&gt;mul&lt;/code&gt; to be 11 for demonstration purpose. Note here I print the time log to the standard error on purpose. The code is listed below.&lt;/p&gt;&#xA;&lt;h2 id=&#34;single-thread-version&#34;&gt;Single Thread Version&#xA;&lt;/h2&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    x &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; mul(&lt;span style=&#34;color:#ae81ff&#34;&gt;11&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    y &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; add(x)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run it!&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; time python3 0_single_thread.py&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time cost &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; mul 2.4840409755706787&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time cost &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; add 2.594242811203003&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time cost &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; mul 2.5620434284210205&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time cost &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; add 2.4484610557556152&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python3 0_single_thread.py  9.81s user 0.01s system 97% cpu 10.111 total&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Both of the two components cost about 2.5 s. (Since I choose the parameter 11 and the magic number 4000000.) The time needed for each iteration becomes long. Besides, while computing one of the components, the other cannot do any computation. The total time for finishing the loop on my machine should be around (2.5 + 2.5) * 2 = 10 s, and I got 11.111 s.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;APXpVNs&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;687px&#34; data-flex-grow=&#34;286&#34; height=&#34;320&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://image.sharefun.dev/APXpVNs.png&#34; srcset=&#34;https://sharefun.dev/APXpVNs_448249732699717023_hu_b45e47f21c554d93.png 800w, https://image.sharefun.dev/APXpVNs.png 917w&#34; width=&#34;917&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;mult-thread-version&#34;&gt;Mult-thread Version&#xA;&lt;/h2&gt;&lt;p&gt;To assure the above sequence, I use Queue for messaging from main thread to &lt;code&gt;t1&lt;/code&gt; (the &lt;code&gt;mul_with_time&lt;/code&gt; thread) and &lt;code&gt;t2&lt;/code&gt; (the &lt;code&gt;add_with_time&lt;/code&gt; thread).&lt;/p&gt;&#xA;&lt;p&gt;The main thread put &lt;code&gt;11&lt;/code&gt; into &lt;code&gt;q1&lt;/code&gt;, the &lt;code&gt;mul_with_time&lt;/code&gt; pop the &lt;code&gt;q1&lt;/code&gt; and do computation and put its result to &lt;code&gt;q2&lt;/code&gt;, the &lt;code&gt;add_with_time&lt;/code&gt; pop &lt;code&gt;q2&lt;/code&gt; and do computation.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mul_with_time&lt;/span&gt;(q1: Queue, q2: Queue) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; int:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    round &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; round &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        n &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; q1&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        q2&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;put(mul(n))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        round &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;add_with_time&lt;/span&gt;(q: Queue) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; int:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    round &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; round &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        n &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; q&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        add(n)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        round &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; __name__ &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    q1 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Queue()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    q2 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Queue()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    t1 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Thread(target&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;mul_with_time, args&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;(q1, q2), daemon&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    t2 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Thread(target&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;add_with_time, args&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;(q2,), daemon&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    t1&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;start()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    t2&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;start()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        q1&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;put(&lt;span style=&#34;color:#ae81ff&#34;&gt;11&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    t1&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;join()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    t2&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;join()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;time python3 1_multi_thread.py &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time cost &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; mul 2.5354559421539307&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time cost &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; mul 6.187425374984741&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time cost &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; mul 6.396909475326538&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time cost &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; mul 2.273833990097046&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python3 1_multi_thread.py  11.17s user 0.02s system 99% cpu 11.228 total&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The total time got even longer! The second round &lt;code&gt;mul_with_time&lt;/code&gt; and the first round &lt;code&gt;add_with_time&lt;/code&gt; are &lt;strong&gt;2.5x&lt;/strong&gt; because these two threads runs simultaneously. Since there is a GIL, only one of them is actually executed at any given moment. And since there is a context switch when transit from one thread to the other, the time for both threads should be more than 2.5 + 2.5 = 5 s.&lt;/p&gt;&#xA;&lt;p&gt;This multi-thread version is a good practice since I have isolated the two components, this architecture makes it possible to execute them concurrently (not parallel).&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;BenastU&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;847px&#34; data-flex-grow=&#34;353&#34; height=&#34;321&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://image.sharefun.dev/BenastU.png&#34; srcset=&#34;https://sharefun.dev/BenastU_17641096395237612115_hu_b255b52f12efdf5b.png 800w, https://image.sharefun.dev/BenastU.png 1134w&#34; width=&#34;1134&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;multi-process-version&#34;&gt;Multi-process Version&#xA;&lt;/h2&gt;&lt;p&gt;Spawning sub-processes for both components can readily avoid them from blocking each other. Simply replace &lt;code&gt;multithreading.Thread&lt;/code&gt; by &lt;code&gt;multiprocessing.Process&lt;/code&gt; and &lt;code&gt;queue.Queue&lt;/code&gt; by &lt;code&gt;multiprocessing.Queue&lt;/code&gt; will turn this script from multi-thread version to multi-process version.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;time python3 2_multi_process.py&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time cost &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; mul 2.4805655479431152&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time cost &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; mul 2.2870962619781494&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time cost &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; mul 2.4712436199188232&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time cost &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; mul 2.320164918899536&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python3 2_multi_process.py  9.58s user 0.02s system 131% cpu 7.313 total&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This time no heavy context switches are present. Each sub-process holds its own GIL and blocks no one. First round &lt;code&gt;add_with_time&lt;/code&gt; and second round &lt;code&gt;mul_with_time&lt;/code&gt; are executed in parallel, i.e. both of them are actually running at a given moment. The total time should be 2.5 + 2.5 + 2.5 = 7.5 s.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;caNLpmW&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;703px&#34; data-flex-grow=&#34;293&#34; height=&#34;316&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://image.sharefun.dev/caNLpmW.png&#34; srcset=&#34;https://sharefun.dev/caNLpmW_12488101972369950257_hu_7b1cf28389581f99.png 800w, https://image.sharefun.dev/caNLpmW.png 926w&#34; width=&#34;926&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;multi-process-with-shell&#34;&gt;Multi-process with shell&#xA;&lt;/h2&gt;&lt;p&gt;The work is done. But when I staring at the &lt;code&gt;2_multi_process.py&lt;/code&gt; script, I found that although &lt;code&gt;mul_with_time&lt;/code&gt; and &lt;code&gt;add_with_time&lt;/code&gt; are well separated, there are many &lt;em&gt;fancy&lt;/em&gt; stuff in my main function. For example, &lt;code&gt;Process&lt;/code&gt; and &lt;code&gt;Queue&lt;/code&gt; are objects that may make other programmers confused at first glance, they are not what I really concern and are not necessary actually.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;Process&lt;/code&gt; can be replaced by shell, and &lt;code&gt;Queue&lt;/code&gt; can be replaced by pipeline &lt;code&gt;|&lt;/code&gt;. Pipe first component&amp;rsquo;s standard output to second component&amp;rsquo;s standard input will make it.&lt;/p&gt;&#xA;&lt;p&gt;3_mp_mul.py&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(mul(&lt;span style=&#34;color:#ae81ff&#34;&gt;11&lt;/span&gt;), flush&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;3_mp_add.py&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; round &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    stdin &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; sys&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;stdin&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;readline()&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rstrip()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (stdin &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;continue&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; add(int(stdin))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        round &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now the two components are even more isolated. In this version, each script is just a main function which listen to the standard input, do single component and then print something to its standard output. (Yes, you can change the first script so that it can listen to standard input too.)&lt;/p&gt;&#xA;&lt;p&gt;And I get the same performance as the previous version.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;time &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;python3 3_mp_mul.py | python3 3_mp_add.py&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time cost &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; mul 2.516085386276245&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time cost &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; add 2.300935745239258&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time cost &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; mul 2.5419352054595947&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time cost &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; add 2.2685813903808594&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; python3 3_mp_mul.py | python3 3_mp_add.py; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  9.64s user 0.02s system 131% cpu 7.349 total&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The parenthesis that enclosing two Python processes is to create a shell sub-process so that the total time of this sub-process (which creates two processes) can be recorded.&lt;/p&gt;&#xA;&lt;p&gt;Imagining that you and your teammates are developing a series of algorithm like &lt;code&gt;sum&lt;/code&gt; and &lt;code&gt;add&lt;/code&gt; which have to be run sequentially and the output of the former is the input of the latter, this architecture frees you from interference each other. You can develop, test your own component, you can also combine it with other components by a pipeline. Neat, right?&lt;/p&gt;&#xA;&lt;p&gt;You can &lt;a class=&#34;link&#34; href=&#34;https://github.com/hfyeh/concurrent_python&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;downlaod&lt;/a&gt; these scripts and run it yourself.&lt;/p&gt;</description>
        </item></channel>
</rss>
