Calls
Introduction
In Turbo-Engine, calls to turbo task functions are central to the operation of the system. This section explains how calls work within the Turbo-Engine framework, including the concepts of unresolved and resolved Vc<T>.
Making Calls
#![allow(unused)]
fn main() {
let vc: Vc<T> = some_turbo_tasks_function();
}
When you invoke a Turbo-Tasks Function, it returns a Vc<T>, which is a pointer to the task’s return value. Here’s what happens during a call:
- Immediate Return: The call returns instantly, and the task is queued for computation.
- Unresolved Vc: The returned
Vcis a so called “unresolved”Vc, meaning it points to a return value that may not yet be computed.
Resolved vs Unresolved Vcs
- Unresolved Vc: An “unresolved”
Vcpoints to a return value of a Task - Resolved Vc: A “resolved”
Vcpoints to a cell computed by a Task.
Resolving Vcs
To compare Vc values or ensure they are ready for use, you can resolve them:
#![allow(unused)]
fn main() {
let resolved = vc.resolve().await?;
}
- Reading: It’s not mandatory to resolve
Vcs before reading them. ReadingVcs will first resolve it and then read the cell value. - Dependency Registration: Resolving a
Vcregisters the current task as a dependent of the task output, ensuring that the task is recomputed if the return value changes. - Usage as Key: Resolving
Vcs is mandatory when using them as keys ofHashMaporHashSetfor the cell identity.
Importance of Resolution
Resolution is crucial for the memoization process:
- Memoization:
Vcs used as arguments are identified by their pointer. - Automatic Resolution: Unresolved
Vcs passed to turbo task functions are resolved automatically, ensuring that functions receive resolvedVcs for memoization.- Intermediate Task: An intermediate task is created internally to handle the resolution of arguments.
Performance Considerations
While automatic resolution is convenient, it introduces the slight overhead of the intermediate Task:
- Manual Resolution: In performance-critical scenarios, resolving
Vcs manually may be beneficial to reduce overhead.
Code Example
Here’s an example of calling a turbo task function and resolving its Vc:
#![allow(unused)]
fn main() {
// Calling a turbo task function
let vc: Vc<MyType> = compute_something();
// Resolving the Vc for direct comparison or use
let resolved_vc: MyType = vc.resolve().await?;
}