6.9 KiB
6.9 KiB
Phase 11.5c: Coroutine実装による非同期処理の完成
🎯 目標
async/await構文を追加し、JITレベルでcoroutineをstate machineに変換して高性能な非同期処理を実現する。
📊 現状と目標
現在の非同期処理
// nowait文(スレッドベース)
nowait result = heavyComputation()
// ...
local value = wait result // FutureBoxから取得
目標の構文
// async/await(coroutineベース)
async function fetchData(url) {
local response = await httpGet(url)
local json = await response.json()
return json.data
}
// 複数の非同期処理
async function fetchAll(urls) {
local promises = []
loop(url in urls) {
promises.push(fetchData(url))
}
return await Promise.all(promises)
}
🚀 実装計画
Step 1: AST拡張
// ast.rs
#[derive(Debug, Clone)]
pub enum ASTNode {
// 既存
Function { name: String, params: Vec<String>, body: Box<ASTNode> },
// 新規追加
AsyncFunction {
name: String,
params: Vec<String>,
body: Box<ASTNode>
},
AwaitExpression {
expression: Box<ASTNode>
},
}
Step 2: MIR Coroutine命令
// mir/instruction.rs
pub enum MirInstruction {
// 既存命令...
// Coroutine関連
/// Coroutine生成
CoroutineCreate {
dst: ValueId,
func: FunctionId,
captures: Vec<ValueId>,
},
/// Yield point(await)
CoroutineYield {
value: ValueId,
resume_label: BasicBlockId,
},
/// Coroutine再開
CoroutineResume {
dst: Option<ValueId>,
coroutine: ValueId,
value: Option<ValueId>,
},
/// Promise結合
PromiseAll {
dst: ValueId,
promises: Vec<ValueId>,
},
}
Step 3: State Machine変換
// mir/coroutine_transform.rs
pub struct CoroutineTransform {
state_enum: HashMap<FunctionId, StateEnum>,
}
/// async関数をstate machineに変換
impl CoroutineTransform {
pub fn transform_async_function(&mut self,
func: &MirFunction
) -> MirFunction {
// 1. await pointsを収集
let await_points = self.collect_await_points(func);
// 2. State enum生成
let states = self.generate_states(await_points);
// 3. State machine関数生成
let state_machine = self.build_state_machine(func, states);
// 4. Coroutine wrapper生成
self.wrap_as_coroutine(state_machine)
}
fn build_state_machine(&self,
func: &MirFunction,
states: Vec<State>
) -> MirFunction {
// switch(state) {
// case State0: ... goto await1 or return
// case State1: ... goto await2 or return
// ...
// }
let mut builder = MirBuilder::new();
// Coroutine state
let state_var = builder.emit_local("state");
let locals = builder.emit_local("locals");
// Main dispatch loop
let loop_bb = builder.create_block();
builder.emit_jump(loop_bb);
builder.switch_to_block(loop_bb);
let state = builder.emit_load(state_var);
// State dispatch
for (i, state) in states.iter().enumerate() {
let state_bb = builder.create_block();
builder.emit_case(state.id, state_bb);
builder.switch_to_block(state_bb);
self.emit_state_code(&mut builder, state);
}
builder.build()
}
}
Step 4: JIT Coroutine最適化
// jit/lower/coroutine.rs
impl<'a> LoweringBuilder<'a> {
/// Coroutineのstack switching最適化
fn emit_coroutine_switch(&mut self,
from: Value,
to: Value
) {
if self.config.use_fast_switch {
// レジスタのみ保存(最適化)
self.emit_save_registers();
self.emit_switch_stack(to);
self.emit_restore_registers();
} else {
// フルコンテキスト保存
self.emit_full_context_save(from);
self.emit_full_context_restore(to);
}
}
/// Inline可能なawaitの検出
fn try_inline_await(&mut self,
await_expr: &MirInstruction
) -> Option<Value> {
// Promise.resolvedなら即値返却
if self.is_resolved_promise(await_expr) {
return Some(self.emit_immediate_value());
}
// 小さなasync関数ならインライン化
if self.is_small_async(await_expr) {
return Some(self.inline_async_call(await_expr));
}
None
}
}
Step 5: ランタイムサポート
// boxes/promise_box.rs
pub struct PromiseBox {
state: Arc<Mutex<PromiseState>>,
base: BoxBase,
}
enum PromiseState {
Pending(Vec<Box<dyn FnOnce(Box<dyn NyashBox>)>>),
Resolved(Box<dyn NyashBox>),
Rejected(String),
}
impl PromiseBox {
pub fn all(promises: Vec<Box<PromiseBox>>) -> Box<PromiseBox> {
// 全Promise完了待ち
let result = PromiseBox::new();
let remaining = Arc::new(AtomicUsize::new(promises.len()));
for (i, promise) in promises.iter().enumerate() {
promise.then(move |value| {
// 結果収集
if remaining.fetch_sub(1, Ordering::SeqCst) == 1 {
result.resolve(collected_values);
}
});
}
Box::new(result)
}
}
📈 期待される効果
パフォーマンス比較
// Before: Thread-based
nowait results = []
loop(url in urls) {
nowait r = httpGet(url) // 新スレッド生成
results.push(r)
}
// After: Coroutine-based
async function fetchAll(urls) {
return await Promise.all(
urls.map(url => httpGet(url)) // Stack switching only
)
}
改善予測
- メモリ使用量: 1/100(スレッドstack vs coroutine state)
- コンテキストスイッチ: 1000倍高速
- 同時接続数: 10,000+対応可能
🔍 検証方法
1. Coroutine統計
{
"total_coroutines": 10000,
"active_coroutines": 500,
"yield_count": 50000,
"average_yield_ns": 100,
"stack_memory_mb": 10
}
2. ベンチマーク
# 10000並行リクエスト
./target/release/nyash bench/async_stress.nyash
# メモリプロファイル
NYASH_COROUTINE_STATS=1 ./target/release/nyash bench/async_memory.nyash
🚧 実装上の注意点
-
Stack管理
- Segmented stack対応
- Stack overflow検出
- GC root scanning
-
エラー伝播
- async境界でのエラー
- Promise rejection chain
-
デバッグ対応
- async stack trace
- Coroutine状態可視化
🎉 完了基準
- async/await構文実装
- MIR coroutine変換
- JIT最適化
- Promise/PromiseBox実装
- 10000並行処理ベンチマーク達成