Part VI: Concurrency#
In this part:
- Async/Await - Async functions, async walkers, async for
- Concurrent Expressions - flow/wait for parallel tasks
Jac supports Python-style async/await for concurrent I/O operations, plus a unique flow/wait syntax for launching and collecting parallel tasks. Use async when you need non-blocking I/O (like HTTP requests), and flow when you want to run multiple independent operations concurrently.
Async/Await#
The async/await syntax works like Python's -- async marks a function as a coroutine, and await suspends execution until the awaited operation completes. Walkers can also be async, enabling non-blocking graph traversal with I/O at each node.
1 Async Functions#
async def fetch_data(url: str) -> dict {
response = await http_get(url);
return await response.json();
}
async def process_multiple(urls: list[str]) -> list[dict] {
results = [];
for url in urls {
data = await fetch_data(url);
results.append(data);
}
return results;
}
2 Async Walkers#
async walker DataFetcher {
has url: str;
async can fetch with `root entry {
data = await http_get(self.url);
report data;
}
}
Use async walker for non-blocking I/O during traversal.
3 Async For Loops#
async def process_stream(stream: AsyncIterator) -> None {
async for item in stream {
print(item);
}
}
Concurrent Expressions#
The flow/wait pattern provides explicit concurrency control. flow launches a task and immediately returns a future (without blocking), while wait retrieves the result (blocking if necessary). This is more explicit than async/await -- you decide exactly when to start parallel work and when to synchronize.
1 flow Keyword#
The flow keyword launches a function call as a background task and returns a future immediately. Use it when you have independent operations that can run in parallel.
def expensive_computation -> int {
return 42;
}
def do_something_else -> int {
return 1;
}
with entry {
future = flow expensive_computation();
# Do other work while computation runs
other_result = do_something_else();
# Wait for result when needed
result = wait future;
}
2 Parallel Operations#
def fetch_users -> list {
return [];
}
def fetch_orders -> list {
return [];
}
def fetch_inventory -> list {
return [];
}
def process_local_data {
# Process local data here
}
with entry {
# Launch multiple operations in parallel
future1 = flow fetch_users();
future2 = flow fetch_orders();
future3 = flow fetch_inventory();
# Continue with other work
process_local_data();
# Collect all results
users = wait future1;
orders = wait future2;
inventory = wait future3;
}
3 flow vs async#
| Feature | async/await | flow/wait |
|---|---|---|
| Model | Event loop (cooperative) | Thread pool (parallel) |
| Best for | I/O-bound, many concurrent | CPU-bound, few concurrent |
| Blocking | Non-blocking | Can block threads |
Learn More#
Related Reference:
- Part I: Foundation - Control flow basics
- Part V: AI Integration - Async LLM calls