title: What is _md5.md5 and why is hashlib.md5 so much slower?
body: <p>Found this undocumented <code>_md5</code> when getting frustrated with the slow stdlib <code>hashlib.md5</code> implementation.</p>
  
  <p>On a macbook:</p>
  
  <pre><code>&gt;&gt;&gt; timeit hashlib.md5(b"hello world")
  597 ns ± 17.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
  &gt;&gt;&gt; timeit _md5.md5(b"hello world")
  224 ns ± 3.18 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
  &gt;&gt;&gt; _md5
  &lt;module '_md5' from '/usr/local/Cellar/python/3.7.6_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/lib-dynload/_md5.cpython-37m-darwin.so'&gt;
  </code></pre>
  
  <p>On a Windows box:</p>
  
  <pre><code>&gt;&gt;&gt; timeit hashlib.md5(b"stonk overflow")
  328 ns ± 21.8 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
  &gt;&gt;&gt; timeit _md5.md5(b"stonk overflow")
  110 ns ± 12.5 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
  &gt;&gt;&gt; _md5
  &lt;module '_md5' (built-in)&gt;
  </code></pre>
  
  <p>On a Linux box:</p>
  
  <pre><code>&gt;&gt;&gt; timeit hashlib.md5(b"https://adventofcode.com/2016/day/5")
  259 ns ± 1.33 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
  &gt;&gt;&gt; timeit _md5.md5(b"https://adventofcode.com/2016/day/5")
  102 ns ± 0.0576 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
  &gt;&gt;&gt; _md5
  &lt;module '_md5' from '/usr/local/lib/python3.8/lib-dynload/_md5.cpython-38-x86_64-linux-gnu.so'&gt;
  </code></pre>
  
  <p>For hashing short messages, it's way faster. For long messages, similar performance.</p>
  
  <p>Why is it hidden away in an underscore extension module, and why isn't this faster implementation used by default in hashlib?  <strong>What is the <code>_md5</code> module</strong> and why doesn't it have public API?</p>