Overview
GPUI provides integrated async runtime for foreground UI updates and background computation.
Key Concepts:
-
Foreground tasks: UI thread, can update entities (cx.spawn )
-
Background tasks: Worker threads, CPU-intensive work (cx.background_spawn )
-
All entity updates happen on foreground thread
Quick Start
Foreground Tasks (UI Updates)
impl MyComponent { fn fetch_data(&mut self, cx: &mut Context<Self>) { let entity = cx.entity().downgrade();
cx.spawn(async move |cx| {
// Runs on UI thread, can await and update entities
let data = fetch_from_api().await;
entity.update(cx, |state, cx| {
state.data = Some(data);
cx.notify();
}).ok();
}).detach();
}
}
Background Tasks (Heavy Work)
impl MyComponent { fn process_file(&mut self, cx: &mut Context<Self>) { let entity = cx.entity().downgrade();
cx.background_spawn(async move {
// Runs on background thread, CPU-intensive
let result = heavy_computation().await;
result
})
.then(cx.spawn(move |result, cx| {
// Back to foreground to update UI
entity.update(cx, |state, cx| {
state.result = result;
cx.notify();
}).ok();
}))
.detach();
}
}
Task Management
struct MyView { _task: Task<()>, // Prefix with _ if stored but not accessed }
impl MyView { fn new(cx: &mut Context<Self>) -> Self { let entity = cx.entity().downgrade();
let _task = cx.spawn(async move |cx| {
// Task automatically cancelled when dropped
loop {
tokio::time::sleep(Duration::from_secs(1)).await;
entity.update(cx, |state, cx| {
state.tick();
cx.notify();
}).ok();
}
});
Self { _task }
}
}
Core Patterns
- Async Data Fetching
cx.spawn(async move |cx| { let data = fetch_data().await?; entity.update(cx, |state, cx| { state.data = Some(data); cx.notify(); })?; Ok::<_, anyhow::Error>(()) }).detach();
- Background Computation + UI Update
cx.background_spawn(async move { heavy_work() }) .then(cx.spawn(move |result, cx| { entity.update(cx, |state, cx| { state.result = result; cx.notify(); }).ok(); })) .detach();
- Periodic Tasks
cx.spawn(async move |cx| { loop { tokio::time::sleep(Duration::from_secs(5)).await; // Update every 5 seconds } }).detach();
- Task Cancellation
Tasks are automatically cancelled when dropped. Store in struct to keep alive.
Common Pitfalls
❌ Don't: Update entities from background tasks
// ❌ Wrong: Can't update entities from background thread cx.background_spawn(async move { entity.update(cx, |state, cx| { // Compile error! state.data = data; }); });
✅ Do: Use foreground task or chain
// ✅ Correct: Chain with foreground task cx.background_spawn(async move { data }) .then(cx.spawn(move |data, cx| { entity.update(cx, |state, cx| { state.data = data; cx.notify(); }).ok(); })) .detach();
Reference Documentation
Complete Guides
API Reference: See api-reference.md
-
Task types, spawning methods, contexts
-
Executors, cancellation, error handling
Patterns: See patterns.md
-
Data fetching, background processing
-
Polling, debouncing, parallel tasks
-
Pattern selection guide
Best Practices: See best-practices.md
-
Error handling, cancellation
-
Performance optimization, testing
-
Common pitfalls and solutions