<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hieu Nguyen</title>
    <description>The latest articles on DEV Community by Hieu Nguyen (@behitek).</description>
    <link>https://dev.to/behitek</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F129542%2Fa86cba0f-b656-4c53-a79d-f61df5879017.jpeg</url>
      <title>DEV Community: Hieu Nguyen</title>
      <link>https://dev.to/behitek</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/behitek"/>
    <language>en</language>
    <item>
      <title>Free Threaded Mode in Python3.13 (GIL disabled)</title>
      <dc:creator>Hieu Nguyen</dc:creator>
      <pubDate>Thu, 10 Oct 2024 13:59:56 +0000</pubDate>
      <link>https://dev.to/behitek/free-threaded-mode-in-python313-gil-disabled-cfc</link>
      <guid>https://dev.to/behitek/free-threaded-mode-in-python313-gil-disabled-cfc</guid>
      <description>&lt;p&gt;Python 3.13 just release recently, with an amazing new feature called "Free threaded mode". This is a great improvement for the performance of your code when you are using threads. This article shows how to enable this feature (not enabled by default) and shows "free threaded mode" impact on the performance of your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Free Threaded Python
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Windows &amp;amp; MacOS users
&lt;/h3&gt;

&lt;p&gt;For Windows and MacOS users, just download the latest installer from &lt;a href="https://www.python.org/downloads/" rel="noopener noreferrer"&gt;Python website&lt;/a&gt;. When you install Python, there is a checkbox to enable "Free threaded mode" when you select "Customize installation" option.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F534ekovphf84okx2iy82.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F534ekovphf84okx2iy82.png" alt="Python Free Threaded Install" width="653" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Ubuntu users
&lt;/h3&gt;

&lt;p&gt;For Ubuntu users, you can enable this feature by running the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;add-apt-repository ppa:deadsnakes
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;python3.13-nogil
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verify Free Threaded Mode is enabled
&lt;/h3&gt;

&lt;p&gt;After installing the package, you can run your code with &lt;code&gt;python3.13&lt;/code&gt; (original) and &lt;code&gt;python3.13-nogil&lt;/code&gt; or &lt;code&gt;python3.13t&lt;/code&gt; (free threaded Python).&lt;/p&gt;

&lt;p&gt;Check out this &lt;a href="https://py-free-threading.github.io/installing_cpython/#linux-distros" rel="noopener noreferrer"&gt;article&lt;/a&gt; for more details on how to install Python 3.13 experimental on Linux distros.&lt;/p&gt;

&lt;p&gt;To verify your Python has "Free threaded mode" enable, you can use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3.13t &lt;span class="nt"&gt;-VV&lt;/span&gt;
Python 3.13.0 experimental free-threading build &lt;span class="o"&gt;(&lt;/span&gt;main, Oct  8 2024, 08:51:28&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;GCC 11.4.0]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Free Threaded Mode Performance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Experiment Setup
&lt;/h3&gt;

&lt;p&gt;Let's see the impact of free threaded mode on a simple code below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I have a function &lt;code&gt;worker&lt;/code&gt; that does some computation and returns the sum of numbers from 0 to 10 million.&lt;/li&gt;
&lt;li&gt;I have the "Test 1" to run the &lt;code&gt;worker&lt;/code&gt; function 5 times, sequentially.&lt;/li&gt;
&lt;li&gt;I have the "Test 2" to run the &lt;code&gt;worker&lt;/code&gt; function in parallel using multiple threads, with number of threads is 5.&lt;/li&gt;
&lt;li&gt;I do measure the execution time of both tests.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Python version : &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nb"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10000000&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;


&lt;span class="n"&gt;n_worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="c1"&gt;# Single thread
&lt;/span&gt;
&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n_worker&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Single Thread: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;seconds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c1"&gt;# Multi thread
&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;threads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n_worker&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Multi Thread: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;seconds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Later, I will run this code with normal Python (&lt;code&gt;python3.13&lt;/code&gt; binary) and free threaded Python (&lt;code&gt;pypy3.13t&lt;/code&gt; binary).&lt;/p&gt;

&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;p&gt;First, run the test with &lt;code&gt;python3.13&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3.13 gil_test.py 
Python version :  3.13.0 (main, Oct  8 2024, 08:51:28) [GCC 11.4.0]
Single Thread:  1.4370562601834536 seconds
Multi Thread:  1.3681392602156848 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, run the test with &lt;code&gt;pypy3.13t&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3.13t gil_test.py 
Python version :  3.13.0 experimental free-threading build (main, Oct  8 2024, 08:51:28) [GCC 11.4.0]
Single Thread:  1.862126287072897 seconds
Multi Thread:  0.3931183419190347 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also trying with &lt;code&gt;python3.11&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3.11 gil_test.py 
Python version :  3.11.3 (main, Apr 25 2023, 16:40:23) [GCC 11.3.0]
Single Thread:  1.753435204969719 seconds
Multi Thread:  1.457715731114149 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Result Analysis
&lt;/h3&gt;

&lt;p&gt;Python default has GIL (Global Interpreter Lock) locking mechanism, making multi-threaded actually not parallel. You can see the time processing of single thread is similar to multi thread.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;python3.11t&lt;/code&gt; (free threaded mode), multi threaded performance is much faster than single threaded. So, multi threading now actually parallel.&lt;/p&gt;

&lt;p&gt;But, do you see Single Thread test in &lt;code&gt;python3.13t&lt;/code&gt; a bit slower than &lt;code&gt;pypy3.13&lt;/code&gt;?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I don't really understand why, so let me know if you have any explanation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I think it is good to use multi threading in python for parallel processing. But, without GIL locking mechanism, it requires developer to be careful about the "thread safety", ie. sharing data between threads.&lt;/p&gt;

&lt;p&gt;Also, we need to wait for libraries and packages update to fully support free threaded mode. That's one of the reason why this "free threaded mode" is not enabled by default for now. But, I think it will be a good feature in future.&lt;/p&gt;

</description>
      <category>python</category>
      <category>gil</category>
    </item>
  </channel>
</rss>
