157 lines
8.9 KiB
HTML
157 lines
8.9 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<title>Rust 异步运行时内部机制 · Tech Sharing</title>
|
||
<link rel="stylesheet" href="../../../assets/fonts.css">
|
||
<link rel="stylesheet" href="../../../assets/base.css">
|
||
<link rel="stylesheet" href="../../../assets/animations/animations.css">
|
||
<link rel="stylesheet" href="style.css">
|
||
</head>
|
||
<body class="tpl-tech-sharing">
|
||
<div class="deck">
|
||
|
||
<!-- 1. Cover -->
|
||
<section class="slide" data-title="Cover">
|
||
<p class="kicker">tech-sharing / 2026-04-15</p>
|
||
<h1 class="h1 anim-fade-up" data-anim="fade-up">Rust 异步运行时<br>到底在<span style="background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent">调度什么</span>?</h1>
|
||
<p class="lede mt-m">从 <span class="mono">Future::poll</span> 到 tokio 的 work-stealing,一次讲清楚。</p>
|
||
<div class="speaker"><div class="av"></div><div><b>@lewis</b><span>platform infra · 45 min + Q&A</span></div></div>
|
||
<div class="deck-footer"><span class="mono">#async #rust #tokio</span><span class="slide-number" data-current="1" data-total="8"></span></div>
|
||
</section>
|
||
|
||
<!-- 2. Agenda -->
|
||
<section class="slide" data-title="Agenda">
|
||
<p class="kicker">agenda.toml</p>
|
||
<h2 class="h2">今天的路线图</h2>
|
||
<div class="stack mt-l">
|
||
<div class="agenda-row"><span class="num">01</span><span class="t">Context: 为什么需要 async</span><span class="d">~5min</span></div>
|
||
<div class="agenda-row"><span class="num">02</span><span class="t">Deep dive 1: Future & Waker</span><span class="d">~12min</span></div>
|
||
<div class="agenda-row"><span class="num">03</span><span class="t">Deep dive 2: Tokio scheduler</span><span class="d">~15min</span></div>
|
||
<div class="agenda-row"><span class="num">04</span><span class="t">Code: 手写一个 mini-runtime</span><span class="d">~8min</span></div>
|
||
<div class="agenda-row"><span class="num">05</span><span class="t">Takeaways + Q&A</span><span class="d">~5min</span></div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 3. Context -->
|
||
<section class="slide" data-title="Context">
|
||
<p class="kicker">// context</p>
|
||
<h2 class="h2">问题:一个线程一个连接,<br>撑不住 10 万并发。</h2>
|
||
<div class="grid g3 mt-l">
|
||
<div class="card card-accent"><h4>Thread-per-conn</h4><p class="dim">每条连接一根 OS 线程,栈 2–8MB。10 万连接 = 几百 GB RAM。</p><span class="tag mt-s">❌ 不现实</span></div>
|
||
<div class="card card-accent"><h4>Event loop (C)</h4><p class="dim">epoll/kqueue + 回调地狱。快,但写起来痛苦且容易出 bug。</p><span class="tag mt-s">😩 callback hell</span></div>
|
||
<div class="card card-accent"><h4>Async / await</h4><p class="dim">看起来像同步代码,编译成状态机。一根线程跑几千任务。</p><span class="tag mt-s">✅ Rust 选这个</span></div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 4. Deep dive 1 -->
|
||
<section class="slide" data-title="Deep Dive 1">
|
||
<p class="kicker">deep-dive · 1 / 2</p>
|
||
<h2 class="h2">Future 其实只有一个方法。</h2>
|
||
<div class="grid g2 mt-l" style="align-items:start">
|
||
<div>
|
||
<p class="lede">编译器把 <span class="mono">async fn</span> 变成一个实现了 <span class="mono">Future</span> trait 的匿名状态机。运行时只做一件事:反复 <span class="mono">poll</span> 它,直到返回 <span class="mono">Ready</span>。</p>
|
||
<div class="mt-l">
|
||
<span class="tag">Pending</span> <span class="tag">Ready(T)</span> <span class="tag">Waker.wake()</span>
|
||
</div>
|
||
</div>
|
||
<div class="terminal">
|
||
<div class="bar"><span class="dot"></span><span class="dot"></span><span class="dot"></span><span>future.rs</span></div>
|
||
<pre><span class="kw">pub trait</span> <span class="fn">Future</span> {
|
||
<span class="kw">type</span> Output;
|
||
<span class="kw">fn</span> <span class="fn">poll</span>(
|
||
<span class="kw">self</span>: Pin<&<span class="kw">mut Self</span>>,
|
||
cx: &<span class="kw">mut</span> Context<<span class="str">'_</span>>,
|
||
) -> Poll<<span class="kw">Self</span>::Output>;
|
||
}
|
||
|
||
<span class="cmt">// Poll::Pending → 挂起,等 waker 唤醒</span>
|
||
<span class="cmt">// Poll::Ready(v) → 完成,产出 v</span></pre>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 5. Deep dive 2 -->
|
||
<section class="slide" data-title="Deep Dive 2">
|
||
<p class="kicker">deep-dive · 2 / 2</p>
|
||
<h2 class="h2">Tokio 是一个偷任务的小工。</h2>
|
||
<div class="grid g2 mt-l" style="align-items:start">
|
||
<div>
|
||
<p class="lede">Multi-thread runtime = N 个 worker,每个 worker 有自己的本地队列。空闲的 worker 会去别人队列里"偷"任务。</p>
|
||
<div class="stack mt-m">
|
||
<div class="tag">✦ local queue · 256 slots</div>
|
||
<div class="tag">✦ global injection queue</div>
|
||
<div class="tag">✦ work-stealing @ 50% steal ratio</div>
|
||
<div class="tag">✦ LIFO slot for cache locality</div>
|
||
</div>
|
||
</div>
|
||
<div class="card" style="padding:32px">
|
||
<h4 class="mono" style="color:var(--accent-2)">scheduler tick loop</h4>
|
||
<div class="stack mt-m" style="font-family:'JetBrains Mono',monospace;font-size:14px;line-height:1.9;color:var(--text-2)">
|
||
<div><span style="color:var(--accent)">1.</span> pop from LIFO slot</div>
|
||
<div><span style="color:var(--accent)">2.</span> else pop from local queue</div>
|
||
<div><span style="color:var(--accent)">3.</span> else drain global queue (every 61 ticks)</div>
|
||
<div><span style="color:var(--accent)">4.</span> else steal from random victim</div>
|
||
<div><span style="color:var(--accent)">5.</span> else park the thread</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 6. Code example -->
|
||
<section class="slide" data-title="Code">
|
||
<p class="kicker">mini-runtime.rs · ~40 LOC</p>
|
||
<h2 class="h2">手写一个最小 runtime。</h2>
|
||
<div class="terminal mt-m">
|
||
<div class="bar"><span class="dot"></span><span class="dot"></span><span class="dot"></span><span>src/main.rs</span></div>
|
||
<pre><span class="kw">use</span> std::collections::VecDeque;
|
||
<span class="kw">use</span> std::sync::{Arc, Mutex};
|
||
<span class="kw">use</span> std::task::{Context, Poll, Wake, Waker};
|
||
|
||
<span class="kw">struct</span> Task(Mutex<Pin<Box<<span class="kw">dyn</span> Future<Output = ()> + Send>>>);
|
||
|
||
<span class="kw">impl</span> Wake <span class="kw">for</span> Task {
|
||
<span class="kw">fn</span> <span class="fn">wake</span>(<span class="kw">self</span>: Arc<<span class="kw">Self</span>>) { QUEUE.lock().unwrap().push_back(<span class="kw">self</span>); }
|
||
}
|
||
|
||
<span class="kw">fn</span> <span class="fn">block_on</span><F: Future<Output = ()> + Send + <span class="str">'static</span>>(fut: F) {
|
||
<span class="fn">spawn</span>(fut);
|
||
<span class="kw">while let Some</span>(task) = QUEUE.lock().unwrap().pop_front() {
|
||
<span class="kw">let</span> waker = Waker::from(task.clone());
|
||
<span class="kw">let mut</span> cx = Context::from_waker(&waker);
|
||
<span class="kw">let mut</span> fut = task.<span class="num">0</span>.lock().unwrap();
|
||
<span class="kw">let</span> _ = fut.as_mut().<span class="fn">poll</span>(&<span class="kw">mut</span> cx); <span class="cmt">// 就是这一行</span>
|
||
}
|
||
}</pre>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 7. Takeaways -->
|
||
<section class="slide" data-title="Takeaways">
|
||
<p class="kicker">// takeaways</p>
|
||
<h2 class="h2">三件事带回去。</h2>
|
||
<div class="grid g3 mt-l">
|
||
<div class="card card-accent"><h4>1 · async 是零成本抽象</h4><p class="dim">编译成状态机,没有运行时虚表,没有 GC。</p></div>
|
||
<div class="card card-accent"><h4>2 · Waker 是脉搏</h4><p class="dim">Future 不主动做事,运行时靠 waker 决定"什么时候再 poll"。</p></div>
|
||
<div class="card card-accent"><h4>3 · 别在 async 里阻塞</h4><p class="dim">一行 <span class="mono">std::fs::read</span> 能让整个 worker 停摆。用 <span class="mono">spawn_blocking</span>。</p></div>
|
||
</div>
|
||
<p class="lede mt-l">延伸阅读:<span class="mono">tokio.rs/blog/2019-10-scheduler</span> · <span class="mono">rust-lang.github.io/async-book</span></p>
|
||
</section>
|
||
|
||
<!-- 8. Q&A -->
|
||
<section class="slide center tc" data-title="Q and A">
|
||
<div>
|
||
<div class="mono" style="font-size:120px;color:var(--accent);font-weight:800;letter-spacing:-.04em">?</div>
|
||
<h2 class="h2">Questions?</h2>
|
||
<p class="lede" style="margin:14px auto">github.com/lewis · @lewis on slack</p>
|
||
<div class="row mt-l" style="justify-content:center">
|
||
<span class="tag">slides: git.co/rt-deck</span>
|
||
<span class="tag">code: git.co/mini-rt</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
</div>
|
||
<script src="../../../assets/runtime.js"></script>
|
||
</body></html>
|