<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://henryonai.github.io/blog</id>
    <title>Henry Hoang Blog</title>
    <updated>2026-03-25T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://henryonai.github.io/blog"/>
    <subtitle>Henry Hoang's Blog</subtitle>
    <icon>https://henryonai.github.io/img/favicon.ico</icon>
    <rights>Copyright © 2026 Henry Hoang.</rights>
    <entry>
        <title type="html"><![CDATA[Python Async vs Sync: 6 Benchmarks That Will Change How You Think About Concurrency]]></title>
        <id>https://henryonai.github.io/blog/python-async-vs-sync-benchmark</id>
        <link href="https://henryonai.github.io/blog/python-async-vs-sync-benchmark"/>
        <updated>2026-03-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Async Python is not always faster. We ran 6 real benchmarks comparing async vs sync — I/O, CPU, SQLAlchemy, memory, latency — and the results may surprise you.]]></summary>
        <content type="html"><![CDATA[<p>"Async makes everything faster" — that's what most developers believe. But is it true? I ran 6 real benchmarks to find out, and the results challenged some of my own assumptions.</p>
<div style="max-width:600px;margin:0 auto"><div style="background-size:cover;background-repeat:no-repeat;position:relative;background-image:url(&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAFCAYAAAB8ZH1oAAAACXBIWXMAABcSAAAXEgFnn9JSAAAAiklEQVR4nDWNyw7CMAwEc0XQNq/aSZvSFEEP8P/fNyhBHCzZ69ldM/pEmznvpPJAloosB6mceNkYnPa/8VI60EA3r4xOCXtFP29Grz+tgW2JecfGpbtv08yUCqE+GeyMjQ3MmJjulHoi69GdVytIyLx042KFoBtTyJiW9D96olOcT+SYuTrtTa36CxF/PtXhfwuJAAAAAElFTkSuQmCC&quot;)"><svg style="width:100%;height:auto;max-width:100%;margin-bottom:-4px" width="640" height="325"></svg><noscript><img style="width:100%;height:auto;max-width:100%;margin-bottom:-4px;position:absolute;top:0;left:0" src="/assets/ideal-img/cover.80e9dfe.640.png" srcset="/assets/ideal-img/cover.80e9dfe.640.png 640w,/assets/ideal-img/cover.c30652c.1030.png 1030w" width="640" height="325"></noscript></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-this-matters">Why This Matters<a href="https://henryonai.github.io/blog/python-async-vs-sync-benchmark#why-this-matters" class="hash-link" aria-label="Direct link to Why This Matters" title="Direct link to Why This Matters" translate="no">​</a></h2>
<p>Python's <code>asyncio</code> has become the default recommendation for "high-performance" applications. FastAPI, aiohttp, asyncpg — the async ecosystem is thriving. But blindly adopting async without understanding <em>when</em> it actually helps can lead to:</p>
<ul>
<li class=""><strong>More complex code</strong> with no performance gain</li>
<li class=""><strong>Worse tail latency</strong> (p99) under load</li>
<li class=""><strong>MissingGreenletError nightmares</strong> in SQLAlchemy</li>
</ul>
<p>I built 6 runnable benchmarks to prove each point with real numbers. All code is <a href="https://github.com/henryonai/blog-code.henryonai.com/tree/main/packages/260325-benchmark-async-vs-sync" target="_blank" rel="noopener noreferrer" class="">open source on GitHub</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="benchmark-1-io-bound--async-wins-big">Benchmark 1: I/O-Bound — Async Wins Big<a href="https://henryonai.github.io/blog/python-async-vs-sync-benchmark#benchmark-1-io-bound--async-wins-big" class="hash-link" aria-label="Direct link to Benchmark 1: I/O-Bound — Async Wins Big" title="Direct link to Benchmark 1: I/O-Bound — Async Wins Big" translate="no">​</a></h2>
<p><strong>Scenario:</strong> 50 HTTP requests, each taking 100ms (simulated with a local mock server).</p>
<div style="max-width:700px;margin:0 auto"><div style="background-size:cover;background-repeat:no-repeat;position:relative;background-image:url(&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAFCAYAAAB8ZH1oAAAACXBIWXMAABcSAAAXEgFnn9JSAAAArklEQVR4nB2MQW6CQABFiRtITFNBMgPDwOhYWoSIaMoCWHatiZdo7AF6iKb1zK8ZVu///Jfv+SvJrdzz6Ht+hoHfYeAxTTP/xpHzruJJaLwgTLg0e777dz7bjvux4952fLncdjS2Yq22eMsw4/qhKQ+WRWwIpMGXBf5MQ6S2CCc+rxXm7URua9LiFWUqsk1Nmpck2pLoF0RmnZgiTEOsLHFqkHmJcKPezT1yr7LgHwgMSWi1gR8ZAAAAAElFTkSuQmCC&quot;)"><svg style="width:100%;height:auto;max-width:100%;margin-bottom:-4px" width="640" height="341"></svg><noscript><img style="width:100%;height:auto;max-width:100%;margin-bottom:-4px;position:absolute;top:0;left:0" src="/assets/ideal-img/01_io_bound_comparison.c78b4c9.640.png" srcset="/assets/ideal-img/01_io_bound_comparison.c78b4c9.640.png 640w,/assets/ideal-img/01_io_bound_comparison.50c868c.1030.png 1030w" width="640" height="341"></noscript></div></div>
<table><thead><tr><th>Approach</th><th>Time</th><th>Speedup</th></tr></thead><tbody><tr><td>Sync (sequential)</td><td>5.18s</td><td>1x</td></tr><tr><td>Threading (10 workers)</td><td>0.53s</td><td>9.8x</td></tr><tr><td><strong>Async (aiohttp)</strong></td><td><strong>0.12s</strong></td><td><strong>43x</strong></td></tr></tbody></table>
<p><strong>Why?</strong> When a sync function waits for I/O, the entire thread blocks. Async suspends the coroutine and lets the event loop handle other tasks while waiting. With 50 concurrent requests, async fires them all simultaneously — total time equals the slowest single request.</p>
<p><strong>Key takeaway:</strong> For high-concurrency I/O workloads (web scraping, API calls, WebSocket), async is the clear winner.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="benchmark-2-cpu-bound--async-has-no-advantage">Benchmark 2: CPU-Bound — Async Has No Advantage<a href="https://henryonai.github.io/blog/python-async-vs-sync-benchmark#benchmark-2-cpu-bound--async-has-no-advantage" class="hash-link" aria-label="Direct link to Benchmark 2: CPU-Bound — Async Has No Advantage" title="Direct link to Benchmark 2: CPU-Bound — Async Has No Advantage" translate="no">​</a></h2>
<p><strong>Scenario:</strong> Calculate sum of primes up to 500,000, repeated 8 times.</p>
<div style="max-width:700px;margin:0 auto"><div style="background-size:cover;background-repeat:no-repeat;position:relative;background-image:url(&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAFCAYAAAB8ZH1oAAAACXBIWXMAABcSAAAXEgFnn9JSAAAAvElEQVR4nB3DS4/BUACA0bscIS1F36S9nVIaj7AibGd0FuKRuIZEImExsRhWbPz2T+IkR3wULbquz6UpubRjbr2Ua6fFf6dFP04wnICyWUPkNIMknaA2T9arB6vFnfXy8S6TMXb9E8uLEHndJO0P+D0otscNu/OW3UmxPyuWWQ+vHlJxQoRm+KRDifprMs8CZiOXbOrxM3H5God4QUzVDRF6yabckNjfXYpRjFaV6HaEZkUUKgEls4Zh+rwAfXlO46S+7iMAAAAASUVORK5CYII=&quot;)"><svg style="width:100%;height:auto;max-width:100%;margin-bottom:-4px" width="640" height="331"></svg><noscript><img style="width:100%;height:auto;max-width:100%;margin-bottom:-4px;position:absolute;top:0;left:0" src="/assets/ideal-img/02_cpu_bound_comparison.76e15e9.640.png" srcset="/assets/ideal-img/02_cpu_bound_comparison.76e15e9.640.png 640w,/assets/ideal-img/02_cpu_bound_comparison.6a3ec51.1030.png 1030w" width="640" height="331"></noscript></div></div>
<table><thead><tr><th>Approach</th><th>Time</th><th>Speedup</th></tr></thead><tbody><tr><td>Sync</td><td>6.2s</td><td>1x</td></tr><tr><td><strong>Async (gather)</strong></td><td><strong>6.2s</strong></td><td><strong>1x (same!)</strong></td></tr><tr><td>Threading</td><td>7.1s</td><td>0.87x (slower!)</td></tr><tr><td><strong>Multiprocessing</strong></td><td><strong>1.8s</strong></td><td><strong>3.4x</strong></td></tr></tbody></table>
<p><strong>Why?</strong> Async runs on a single thread. CPU-bound work never yields to the event loop — there's no I/O to wait for. Threading is even <em>worse</em> due to the GIL (Global Interpreter Lock) adding overhead. Only <code>multiprocessing</code> achieves true parallelism by using separate processes with separate GILs.</p>
<p><strong>Key takeaway:</strong> For CPU-heavy tasks (ML inference, image processing, data crunching), use <code>multiprocessing</code> or <code>concurrent.futures.ProcessPoolExecutor</code>. Async is pointless here.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="benchmark-3-sqlalchemy--sync-beats-async-on-localhost">Benchmark 3: SQLAlchemy — Sync Beats Async on Localhost<a href="https://henryonai.github.io/blog/python-async-vs-sync-benchmark#benchmark-3-sqlalchemy--sync-beats-async-on-localhost" class="hash-link" aria-label="Direct link to Benchmark 3: SQLAlchemy — Sync Beats Async on Localhost" title="Direct link to Benchmark 3: SQLAlchemy — Sync Beats Async on Localhost" translate="no">​</a></h2>
<p><strong>Scenario:</strong> Concurrent database queries via SQLAlchemy ORM — sync (psycopg2 + ThreadPoolExecutor) vs async (asyncpg).</p>
<div style="max-width:700px;margin:0 auto"><div style="background-size:cover;background-repeat:no-repeat;position:relative;background-image:url(&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAGCAYAAAD68A/GAAAACXBIWXMAABcSAAAXEgFnn9JSAAAA2UlEQVR4nB3KS07CQACA4Ym6UhNMC8P0NY8ybVOolUSjNjSElUEMG1ZGDuBZPIPRDSfxPO7cufpN/NafGAQKX8wopnNc2aAnNXnZIF1N6CrqpiXVDqHSCda3ZHlNbErizHOmDPtmztviHu8dNneISHvCyDKMHTIr/uOxNByWPb+7J1RWEcQ5QiYOrQus9gShREWGk7HlfdHxvX1gNBoTyAQxSByffcfXZkO12mPrO46GCR99x89uy9X6FX25QpwHitvUsJ5dU/TPSNtyeiFpE8PjtKVaviD9DX96+1uzdN14OwAAAABJRU5ErkJggg==&quot;)"><svg style="width:100%;height:auto;max-width:100%;margin-bottom:-4px" width="640" height="358"></svg><noscript><img style="width:100%;height:auto;max-width:100%;margin-bottom:-4px;position:absolute;top:0;left:0" src="/assets/ideal-img/03_sqlalchemy_throughput.0c20f48.640.png" srcset="/assets/ideal-img/03_sqlalchemy_throughput.0c20f48.640.png 640w,/assets/ideal-img/03_sqlalchemy_throughput.84d349d.1030.png 1030w" width="640" height="358"></noscript></div></div>
<table><thead><tr><th>Concurrency</th><th>Sync (q/s)</th><th>Async (q/s)</th><th>Winner</th></tr></thead><tbody><tr><td>Low (10)</td><td>1,892</td><td>704</td><td>Sync 2.7x</td></tr><tr><td>High (100)</td><td>6,287</td><td>791</td><td>Sync 7.9x</td></tr></tbody></table>
<p><strong>Surprise!</strong> Sync is significantly faster for localhost PostgreSQL. Why?</p>
<ol>
<li class=""><strong>Localhost queries are sub-millisecond</strong> — there's almost no I/O wait time for async to exploit</li>
<li class=""><strong>asyncpg + SQLAlchemy ORM overhead</strong> — the async driver adds event loop scheduling cost on top of ORM overhead</li>
<li class=""><strong>ThreadPoolExecutor is well-optimized</strong> — OS thread scheduling is very efficient for short-lived tasks</li>
</ol>
<p><strong>Key takeaway:</strong> Async database access shines with <strong>remote databases</strong> where network latency is significant (5-50ms per query). For localhost or same-datacenter connections, sync is often faster and simpler.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="benchmark-4-memory--coroutines-use-107x-less">Benchmark 4: Memory — Coroutines Use 107x Less<a href="https://henryonai.github.io/blog/python-async-vs-sync-benchmark#benchmark-4-memory--coroutines-use-107x-less" class="hash-link" aria-label="Direct link to Benchmark 4: Memory — Coroutines Use 107x Less" title="Direct link to Benchmark 4: Memory — Coroutines Use 107x Less" translate="no">​</a></h2>
<p><strong>Scenario:</strong> Create 1,000 concurrent tasks — threads vs coroutines.</p>
<div style="max-width:700px;margin:0 auto"><div style="background-size:cover;background-repeat:no-repeat;position:relative;background-image:url(&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAECAYAAAC3OK7NAAAACXBIWXMAABcSAAAXEgFnn9JSAAAAiklEQVR4nC3DTQqCQACAUVcpBGVqjv+NU7YJcqZdOHqcVkZ0lbYWHfULpAfPcYOEoT7w6a5Mg+XdW6be8h0sL9txbE5sRIXj+TFtIXmaC2NruGvDqA0PbbidNWXVEGU1zjpM8TPFsmxYiN3cnUu8RLLN1dxZBYIwrRG5Ik4labH/VyS5IkoqAlHyA08DO4+Ufn99AAAAAElFTkSuQmCC&quot;)"><svg style="width:100%;height:auto;max-width:100%;margin-bottom:-4px" width="640" height="279"></svg><noscript><img style="width:100%;height:auto;max-width:100%;margin-bottom:-4px;position:absolute;top:0;left:0" src="/assets/ideal-img/04_memory_comparison.d718814.640.png" srcset="/assets/ideal-img/04_memory_comparison.d718814.640.png 640w,/assets/ideal-img/04_memory_comparison.9930704.1030.png 1030w" width="640" height="279"></noscript></div></div>
<table><thead><tr><th>Approach</th><th>Peak RSS Delta</th></tr></thead><tbody><tr><td>1,000 Threads</td><td>35.2 MB</td></tr><tr><td>1,000 Coroutines</td><td>0.33 MB</td></tr><tr><td><strong>Ratio</strong></td><td><strong>107x</strong></td></tr></tbody></table>
<p>Each OS thread requires a stack (typically 1-8 MB). A coroutine is just a Python object — roughly 1 KB. At scale (10,000+ concurrent connections), this difference becomes critical, especially in containerized environments with memory limits.</p>
<p><strong>Key takeaway:</strong> If you need thousands of concurrent connections (WebSocket servers, chat systems, IoT gateways), async is the only viable option from a memory perspective.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="benchmark-5-missinggreenleterror--the-1-async-sqlalchemy-trap">Benchmark 5: MissingGreenletError — The #1 Async SQLAlchemy Trap<a href="https://henryonai.github.io/blog/python-async-vs-sync-benchmark#benchmark-5-missinggreenleterror--the-1-async-sqlalchemy-trap" class="hash-link" aria-label="Direct link to Benchmark 5: MissingGreenletError — The #1 Async SQLAlchemy Trap" title="Direct link to Benchmark 5: MissingGreenletError — The #1 Async SQLAlchemy Trap" translate="no">​</a></h2>
<p>This isn't a performance benchmark — it's a <strong>correctness</strong> demonstration. The most common error when migrating from sync to async SQLAlchemy.</p>
<div style="max-width:700px;margin:0 auto"><div style="background-size:cover;background-repeat:no-repeat;position:relative;background-image:url(&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAFCAYAAAB8ZH1oAAAACXBIWXMAABcSAAAXEgFnn9JSAAAAhUlEQVR4nG3KyQ6CMBRG4e4pdoKOVFQ0DsHo+7/cMdS4c/El5/65QmqPC5VYF8Y8t/bTkbScyOcTNkz0Q0QYG3mlyuwinUlIHehdxN9W/H1F+4JKCeGGzJwPlLhnZxPSBLTLLNcnl8cbPRak8ojeBKSNzdYb5SKlJOqUWm9be/ynU1+/+wNSeT8AYCzp1wAAAABJRU5ErkJggg==&quot;)"><svg style="width:100%;height:auto;max-width:100%;margin-bottom:-4px" width="640" height="324"></svg><noscript><img style="width:100%;height:auto;max-width:100%;margin-bottom:-4px;position:absolute;top:0;left:0" src="/assets/ideal-img/05_greenlet_error_flow.376f368.640.png" srcset="/assets/ideal-img/05_greenlet_error_flow.376f368.640.png 640w,/assets/ideal-img/05_greenlet_error_flow.8ca214d.1030.png 1030w" width="640" height="324"></noscript></div></div>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># SYNC — works fine</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">author </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> session</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Author</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">author</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">books  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Lazy loading: implicit SQL query runs automatically</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># ASYNC — CRASHES!</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">author </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> session</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Author</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">author</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">books  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># MissingGreenletError: implicit I/O forbidden in async</span><br></span></code></pre></div></div>
<p><strong>Why?</strong> Lazy loading performs an implicit database query when you access a relationship attribute. In async context, all I/O must be explicitly <code>await</code>ed. Python's attribute access (<code>author.books</code>) cannot be awaited.</p>
<p><strong>Three fixes:</strong></p>
<table><thead><tr><th>Fix</th><th>Code</th><th>Best For</th></tr></thead><tbody><tr><td><code>selectinload()</code></td><td><code>.options(selectinload(Author.books))</code></td><td>Collections (recommended)</td></tr><tr><td><code>joinedload()</code></td><td><code>.options(joinedload(Author.books))</code></td><td>One-to-one relationships</td></tr><tr><td><code>AsyncAttrs</code> mixin</td><td><code>await author.awaitable_attrs.books</code></td><td>Occasional access</td></tr></tbody></table>
<p><strong>Key takeaway:</strong> Before migrating to async SQLAlchemy, audit every relationship access in your codebase. Set <code>lazy="raise"</code> during development to catch missing eager loads early.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="benchmark-6-latency-variance--async-p99-is-29x-higher">Benchmark 6: Latency Variance — Async p99 Is 29x Higher<a href="https://henryonai.github.io/blog/python-async-vs-sync-benchmark#benchmark-6-latency-variance--async-p99-is-29x-higher" class="hash-link" aria-label="Direct link to Benchmark 6: Latency Variance — Async p99 Is 29x Higher" title="Direct link to Benchmark 6: Latency Variance — Async p99 Is 29x Higher" translate="no">​</a></h2>
<p><strong>Scenario:</strong> 100 concurrent queries, measure per-query latency at p50, p95, p99.</p>
<div style="max-width:700px;margin:0 auto"><div style="background-size:cover;background-repeat:no-repeat;position:relative;background-image:url(&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAFCAYAAAB8ZH1oAAAACXBIWXMAABcSAAAXEgFnn9JSAAAAyklEQVR4nAXBu07CUACA4fMEaLCU9pz29EK1Vm0gXIItFAKLm4MbDDoZJxITEzcnwwAJA4MhJg4MyIarj/fzfaJUtjAqCumE2DrixPaoSg+pI6SfULZ8Tg2JMCyN7dRIw5jb8ysy7aPSMd3HJZ3pnM7kk+7TCmGoEFOF7Ad9vos+X60UK3vg7uOf4euOYrZl9P6H8FRAI0rY9nLWecaifo3Zvmf0diB/+SF/3lDMfhFu1SFRHrFyuXQ0F1JxJgPcuIldSzH9G8ygzhEBKVMh/9H8vAAAAABJRU5ErkJggg==&quot;)"><svg style="width:100%;height:auto;max-width:100%;margin-bottom:-4px" width="640" height="309"></svg><noscript><img style="width:100%;height:auto;max-width:100%;margin-bottom:-4px;position:absolute;top:0;left:0" src="/assets/ideal-img/06_latency_variance.50785da.640.png" srcset="/assets/ideal-img/06_latency_variance.50785da.640.png 640w,/assets/ideal-img/06_latency_variance.edfb514.1030.png 1030w" width="640" height="309"></noscript></div></div>
<table><thead><tr><th>Percentile</th><th>Sync</th><th>Async</th><th>Ratio</th></tr></thead><tbody><tr><td>p50 (median)</td><td>4.6ms</td><td>1,165ms</td><td>253x</td></tr><tr><td>p95</td><td>38.4ms</td><td>1,185ms</td><td>31x</td></tr><tr><td>p99</td><td>41.2ms</td><td>1,192ms</td><td>29x</td></tr></tbody></table>
<p><strong>Why?</strong> This is <a href="https://calpaterson.com/async-python-is-not-faster.html" target="_blank" rel="noopener noreferrer" class="">Cal Paterson's finding</a> proven in practice:</p>
<ul>
<li class=""><strong>Sync (threads):</strong> OS preemptive scheduler distributes CPU time fairly across threads. No single request starves.</li>
<li class=""><strong>Async (event loop):</strong> Cooperative scheduling — if one coroutine takes longer than expected, all other waiting coroutines are delayed. The event loop is single-threaded.</li>
</ul>
<p><strong>Key takeaway:</strong> If your SLA requires low p99 latency (real-time trading, gaming, health monitoring), sync with thread pools may be more predictable than async.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-decision-framework">The Decision Framework<a href="https://henryonai.github.io/blog/python-async-vs-sync-benchmark#the-decision-framework" class="hash-link" aria-label="Direct link to The Decision Framework" title="Direct link to The Decision Framework" translate="no">​</a></h2>
<p>Here's my practical guide after running these benchmarks:</p>
<table><thead><tr><th>Scenario</th><th>Use</th><th>Why</th></tr></thead><tbody><tr><td><strong>High-concurrency I/O</strong> (100+ connections)</td><td>Async</td><td>40x faster, 107x less memory</td></tr><tr><td><strong>CPU-heavy computation</strong></td><td>Multiprocessing</td><td>3.4x faster, true parallelism</td></tr><tr><td><strong>Localhost database</strong></td><td>Sync</td><td>8x faster, simpler code</td></tr><tr><td><strong>Remote database</strong> (5ms+ latency)</td><td>Async</td><td>Overlaps I/O waits</td></tr><tr><td><strong>Strict p99 requirements</strong></td><td>Sync</td><td>29x lower tail latency</td></tr><tr><td><strong>Simple scripts / CLIs</strong></td><td>Sync</td><td>KISS — no async complexity</td></tr><tr><td><strong>WebSocket / real-time</strong></td><td>Async</td><td>Memory-efficient at scale</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="run-it-yourself">Run It Yourself<a href="https://henryonai.github.io/blog/python-async-vs-sync-benchmark#run-it-yourself" class="hash-link" aria-label="Direct link to Run It Yourself" title="Direct link to Run It Yourself" translate="no">​</a></h2>
<p>All benchmarks are open source and reproducible:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain"># Clone and setup</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">git clone https://github.com/henryonai/blog-code.henryonai.com</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">cd blog-code.henryonai.com</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">make setup</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># Run non-DB demos</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">cd packages/260325-benchmark-async-vs-sync</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">make run-all</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># Run with PostgreSQL</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">make docker-up</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">make test-db</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># Generate charts</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">make charts</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="final-thoughts">Final Thoughts<a href="https://henryonai.github.io/blog/python-async-vs-sync-benchmark#final-thoughts" class="hash-link" aria-label="Direct link to Final Thoughts" title="Direct link to Final Thoughts" translate="no">​</a></h2>
<p>Async Python is a powerful tool — but it's not a silver bullet. The most important lesson from these benchmarks:</p>
<blockquote>
<p><strong>Async excels at waiting efficiently. It doesn't make your code run faster — it makes your code wait smarter.</strong></p>
</blockquote>
<p>Before reaching for <code>async/await</code>, ask yourself: "Is my bottleneck I/O wait time, or actual computation?" If it's I/O with high concurrency, async is your friend. For everything else, sync is simpler, more predictable, and often faster.</p>
<p>The Python 3.13 free-threaded mode (no GIL) may change this calculus in the future — but that's a topic for another benchmark.</p>]]></content>
        <author>
            <name>Henry Hoang</name>
            <uri>https://henryonai.github.io/</uri>
        </author>
        <category label="Python" term="Python"/>
        <category label="Performance" term="Performance"/>
        <category label="Backend" term="Backend"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Preparing for the AWS Certified AI Practitioner (AIF-C01) Exam]]></title>
        <id>https://henryonai.github.io/blog/preparing-for-the-aws-certified-ai-practitioner-aif-c01-exam</id>
        <link href="https://henryonai.github.io/blog/preparing-for-the-aws-certified-ai-practitioner-aif-c01-exam"/>
        <updated>2026-03-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Resources and study guide for the AWS Certified AI Practitioner (AIF-C01) exam.]]></summary>
        <content type="html"><![CDATA[<p>Preparing for the AWS Certified AI Practitioner (AIF-C01) exam? These are the essential links, study materials, and exam tips to help you get certified.</p>
<div style="max-width:320px;margin:0 auto"><div style="background-size:cover;background-repeat:no-repeat;position:relative;background-image:url(&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAACXBIWXMAAAsSAAALEgHS3X78AAABZklEQVR4nE2Qu04CUQBEr1b6BVT+gjHRRFFkDS8xICwCy0sIDyEoLI8ALmFR0CzGCI1YmZDwEzYUmEhBsQWF1NbQU+8dA2i0mUwmp5lDAKwQQlYJIWQ6namq0lOn8vDc+ZpBNd8Iqa3+MIQAWG+/djMFUZqkBQk5/hJCiZ80Xro8gLUFNB6PN4T6o+yJ8PBFeVq6bSpiuaD4vW5qcESQzFfkOUOGo0+Gi/Aw2gOKlYtS1heHhYtDZwvSHcaqHFl8GMgyQ3r9D63zPAm7Nw7dqY8Wqw0kcyLUepaqDWc4NLvw1utryTwc/gQy13UURIlW75u4kVrICnXKhVPY1bFLcCCPGCsXg80TU4KJPHWHrmBxR8CFU1Rz7FK2GRvehzKzOJMqVmV3OA0TG6QGm1/Z07PKgdFFTY4Q/BfZ5ZlfPVKznXEEEpMtjQWb+ycwO8MTsdH60/NfOABVrnzX4YVaZ96XwslC+Df268eF7ra7XQAAAABJRU5ErkJggg==&quot;)"><svg style="width:100%;height:auto;max-width:100%;margin-bottom:-4px" width="600" height="600"></svg><noscript><img style="width:100%;height:auto;max-width:100%;margin-bottom:-4px;position:absolute;top:0;left:0" src="/assets/ideal-img/aws-certified-ai-practitioner.0631ef5.600.png" srcset="/assets/ideal-img/aws-certified-ai-practitioner.0631ef5.600.png 600w" width="600" height="600"></noscript></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="official-certification-links">Official Certification Links<a href="https://henryonai.github.io/blog/preparing-for-the-aws-certified-ai-practitioner-aif-c01-exam#official-certification-links" class="hash-link" aria-label="Direct link to Official Certification Links" title="Direct link to Official Certification Links" translate="no">​</a></h2>
<ul>
<li class=""><a href="https://aws.amazon.com/certification/certified-ai-practitioner/" target="_blank" rel="noopener noreferrer" class="">Certification home page</a></li>
<li class=""><a href="https://d1.awsstatic.com/training-and-certification/docs-ai-practitioner/AWS-Certified-AI-Practitioner_Exam-Guide.pdf?p=cert&amp;c=ai&amp;z=3" target="_blank" rel="noopener noreferrer" class="">Exam guide</a></li>
<li class=""><a href="https://skillbuilder.aws/exam-prep/ai-practitioner?p=cert&amp;c=ai&amp;z=3" target="_blank" rel="noopener noreferrer" class="">4-step prep resources</a></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="major-categories-of-exam-topics">Major Categories of Exam Topics<a href="https://henryonai.github.io/blog/preparing-for-the-aws-certified-ai-practitioner-aif-c01-exam#major-categories-of-exam-topics" class="hash-link" aria-label="Direct link to Major Categories of Exam Topics" title="Direct link to Major Categories of Exam Topics" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="machine-learning-basics">Machine Learning Basics<a href="https://henryonai.github.io/blog/preparing-for-the-aws-certified-ai-practitioner-aif-c01-exam#machine-learning-basics" class="hash-link" aria-label="Direct link to Machine Learning Basics" title="Direct link to Machine Learning Basics" translate="no">​</a></h3>
<ul>
<li class="">Types of machine learning problems (supervised, unsupervised, reinforcement, classification, regression, etc.) (<a href="https://youtu.be/6LZuIkWMlhk" target="_blank" rel="noopener noreferrer" class="">YouTube video</a>)<!-- -->
<ul>
<li class="">Labeled data vs. unlabeled data and what kinds of problems require which</li>
</ul>
</li>
<li class="">The machine learning lifecycle (framing the problem, data processing, model development, model training, deployment/inference, monitoring)</li>
<li class="">Ways to score/evaluate model performance (accuracy, precision, recall, F1 score, BERTScore, ROUGE, BLEU, etc.)</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="generative-ai-basics">Generative AI Basics<a href="https://henryonai.github.io/blog/preparing-for-the-aws-certified-ai-practitioner-aif-c01-exam#generative-ai-basics" class="hash-link" aria-label="Direct link to Generative AI Basics" title="Direct link to Generative AI Basics" translate="no">​</a></h3>
<ul>
<li class="">Differences between generative AI and traditional ML/AI</li>
<li class="">Fine-tuning vs. RAG vs. domain tuning (<a href="https://youtu.be/L7PfLk4a2oY" target="_blank" rel="noopener noreferrer" class="">YouTube video for Fine-tuning vs. RAG</a>)</li>
<li class="">Reinforcement learning from human feedback (RLHF)</li>
<li class="">Prompt engineering (zero-shot, few-shot, parameter tuning with things like temperature, Top P, injection attacks, etc.)</li>
<li class="">Vector embeddings and the OpenSearch Service (see <a href="https://youtu.be/4esqnMlMo8I" target="_blank" rel="noopener noreferrer" class="">Lex/Bedrock video</a>, <a href="https://youtu.be/vr0MHUMZPv8" target="_blank" rel="noopener noreferrer" class="">How Vector Embeddings Work</a>)</li>
<li class="">General concepts around least effort, lowest operational overhead, lowest cost, etc.</li>
<li class="">Responsible AI</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="sagemaker">SageMaker<a href="https://henryonai.github.io/blog/preparing-for-the-aws-certified-ai-practitioner-aif-c01-exam#sagemaker" class="hash-link" aria-label="Direct link to SageMaker" title="Direct link to SageMaker" translate="no">​</a></h3>
<ul>
<li class="">Important! Know all the core features/capabilities: <a href="https://youtu.be/tB0WrVlYhc4" target="_blank" rel="noopener noreferrer" class="">Data Wrangler</a>, <a href="https://youtu.be/BP0_QYRN8zU" target="_blank" rel="noopener noreferrer" class="">Feature Store</a>, <a href="https://aws.amazon.com/sagemaker-ai/clarify/" target="_blank" rel="noopener noreferrer" class="">Clarify</a>, <a href="https://aws.amazon.com/sagemaker-ai/jumpstart/" target="_blank" rel="noopener noreferrer" class="">JumpStart</a>, <a href="https://docs.aws.amazon.com/sagemaker/latest/dg/model-monitor.html" target="_blank" rel="noopener noreferrer" class="">Model Monitor</a>, <a href="https://aws.amazon.com/sagemaker-ai/groundtruth/" target="_blank" rel="noopener noreferrer" class="">Ground Truth</a>, <a href="https://youtu.be/7v1-uQ0lCuQ" target="_blank" rel="noopener noreferrer" class="">SageMaker Canvas</a>, <a href="https://youtu.be/ue7LuQtE6Pw" target="_blank" rel="noopener noreferrer" class="">SageMaker Studio Lab</a> [free], etc.<!-- -->
<ul>
<li class="">(Note: Some of the SageMaker videos are slightly outdated 🙂)</li>
<li class="">Review <a href="https://youtu.be/iVIcl-546qA" target="_blank" rel="noopener noreferrer" class="">a high-level explanation</a> of SageMaker and recent changes</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="aws-ai-and-ml-services">AWS AI and ML Services<a href="https://henryonai.github.io/blog/preparing-for-the-aws-certified-ai-practitioner-aif-c01-exam#aws-ai-and-ml-services" class="hash-link" aria-label="Direct link to AWS AI and ML Services" title="Direct link to AWS AI and ML Services" translate="no">​</a></h3>
<ul>
<li class="">Know all the major AI/ML services and their use cases<!-- -->
<ul>
<li class=""><a href="https://youtu.be/PyjDVZ--cfs" target="_blank" rel="noopener noreferrer" class="">Rekognition</a>, <a href="https://aws.amazon.com/lex/getting-started/?nc=sn&amp;loc=4" target="_blank" rel="noopener noreferrer" class="">Lex</a>, <a href="https://aws.amazon.com/polly/getting-started/?nc=sn&amp;loc=5" target="_blank" rel="noopener noreferrer" class="">Polly</a>, <a href="https://aws.amazon.com/textract/features/" target="_blank" rel="noopener noreferrer" class="">Textract</a>, <a href="https://aws.amazon.com/transcribe/getting-started/?nc=sn&amp;loc=4" target="_blank" rel="noopener noreferrer" class="">Transcribe</a>, <a href="https://aws.amazon.com/comprehend/features/" target="_blank" rel="noopener noreferrer" class="">Comprehend</a>, <a href="https://aws.amazon.com/augmented-ai/" target="_blank" rel="noopener noreferrer" class="">Augmented AI (A2I)</a></li>
<li class="">Pay special attention to <a href="https://youtu.be/32D7NJK9QIk" target="_blank" rel="noopener noreferrer" class="">Bedrock</a> and foundational models</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="other-core-aws-services">Other Core AWS Services<a href="https://henryonai.github.io/blog/preparing-for-the-aws-certified-ai-practitioner-aif-c01-exam#other-core-aws-services" class="hash-link" aria-label="Direct link to Other Core AWS Services" title="Direct link to Other Core AWS Services" translate="no">​</a></h3>
<ul>
<li class="">Have a foundational understanding of core services and how they can interact with the AI/ML services<!-- -->
<ul>
<li class=""><a href="https://youtu.be/hAk-7ImN6iM" target="_blank" rel="noopener noreferrer" class="">IAM</a></li>
<li class=""><a href="https://youtu.be/YH_DVenJHII" target="_blank" rel="noopener noreferrer" class="">EC2</a></li>
<li class=""><a href="https://youtu.be/vp_uulb5phM" target="_blank" rel="noopener noreferrer" class="">RDS</a> / <a href="https://youtu.be/FQrN5aJWa_U" target="_blank" rel="noopener noreferrer" class="">DynamoDB</a></li>
<li class=""><a href="https://youtu.be/7_NNlnH7sAg" target="_blank" rel="noopener noreferrer" class="">VPC</a></li>
<li class=""><a href="https://youtu.be/mDRoyPFJvlU" target="_blank" rel="noopener noreferrer" class="">S3</a></li>
<li class=""><a href="https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-user-guide.html" target="_blank" rel="noopener noreferrer" class="">CloudTrail</a></li>
<li class=""><a href="https://docs.aws.amazon.com/macie/latest/user/what-is-macie.html" target="_blank" rel="noopener noreferrer" class="">Macie</a></li>
<li class=""><a href="https://docs.aws.amazon.com/quicksight/latest/user/welcome.html" target="_blank" rel="noopener noreferrer" class="">QuickSight</a></li>
</ul>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-study">How to Study<a href="https://henryonai.github.io/blog/preparing-for-the-aws-certified-ai-practitioner-aif-c01-exam#how-to-study" class="hash-link" aria-label="Direct link to How to Study" title="Direct link to How to Study" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="if-youre-a-total-newbie">If you're a total newbie<a href="https://henryonai.github.io/blog/preparing-for-the-aws-certified-ai-practitioner-aif-c01-exam#if-youre-a-total-newbie" class="hash-link" aria-label="Direct link to If you're a total newbie" title="Direct link to If you're a total newbie" translate="no">​</a></h3>
<ul>
<li class="">Follow the <a href="https://skillbuilder.aws/exam-prep/ai-practitioner?p=cert&amp;c=ai&amp;z=3" target="_blank" rel="noopener noreferrer" class="">AWS 4-step plan</a></li>
<li class="">Many resources are free and don't require a subscription</li>
<li class="">Do practice questions and practice exam to gauge how you're doing (all questions have full explanations and additional links)</li>
<li class="">Check out courses on other platforms too</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="if-you-have-mlai-experience-on-aws">If you have ML/AI experience on AWS<a href="https://henryonai.github.io/blog/preparing-for-the-aws-certified-ai-practitioner-aif-c01-exam#if-you-have-mlai-experience-on-aws" class="hash-link" aria-label="Direct link to If you have ML/AI experience on AWS" title="Direct link to If you have ML/AI experience on AWS" translate="no">​</a></h3>
<ul>
<li class="">Do practice questions and practice exam to identify where you have gaps, then study for those</li>
<li class="">Skip around AWS courses as needed, and check out content on other platforms too</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="exam-tips">Exam Tips<a href="https://henryonai.github.io/blog/preparing-for-the-aws-certified-ai-practitioner-aif-c01-exam#exam-tips" class="hash-link" aria-label="Direct link to Exam Tips" title="Direct link to Exam Tips" translate="no">​</a></h2>
<ul>
<li class="">Read the questions carefully<!-- -->
<ul>
<li class="">Look for qualifier phrases such as "least expensive," or "with the least amount of effort"</li>
<li class="">There may be more than one correct answer</li>
</ul>
</li>
<li class="">You can usually eliminate two answers right away because they don't make sense ("the distractors")</li>
<li class="">Correct answers:<!-- -->
<ul>
<li class="">Are usually simple</li>
<li class="">Usually involve an AWS managed service</li>
</ul>
</li>
<li class="">Make your first pass through all questions, answering things you're sure of<!-- -->
<ul>
<li class="">Flag the others to come back to</li>
<li class="">Make a second pass on all questions if you have time</li>
<li class="">Sometimes a question later in the exam will help you remember an earlier answer</li>
</ul>
</li>
<li class="">Never leave a question unanswered<!-- -->
<ul>
<li class="">It will automatically be marked wrong</li>
<li class="">Guessing at least gives you a chance</li>
</ul>
</li>
<li class="">Take the official practice questions and practice exam</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="practice-questions">Practice Questions<a href="https://henryonai.github.io/blog/preparing-for-the-aws-certified-ai-practitioner-aif-c01-exam#practice-questions" class="hash-link" aria-label="Direct link to Practice Questions" title="Direct link to Practice Questions" translate="no">​</a></h2>
<ul>
<li class=""><a href="https://henryonai.github.io/cloud/category/aws-certified-ai-practitioner-practical-exam-aif-c01-3/" target="_blank" rel="noopener noreferrer" class="">AWS Certified AI Practitioner (AIF-C01) Practice Questions</a></li>
</ul>]]></content>
        <author>
            <name>Henry Hoang</name>
            <uri>https://henryonai.github.io/</uri>
        </author>
        <category label="AWS" term="AWS"/>
        <category label="AI" term="AI"/>
        <category label="Certification" term="Certification"/>
        <category label="Cloud" term="Cloud"/>
    </entry>
</feed>