revival of the async-io functions

This commit is contained in:
Chris Boesch
2026-04-02 10:28:40 +02:00
parent e22748d488
commit 3b22bfd898
2 changed files with 67 additions and 39 deletions

View File

@@ -1,54 +1,71 @@
// //
// The power and purpose of async/await becomes more apparent // Sometimes you want to race multiple tasks and act on whichever
// when we do multiple things concurrently. Foo and Bar do not // finishes first. That's what Select is for!
// depend on each other and can happen at the same time, but End
// requires that they both be finished.
// //
// +---------+ // Select is like a Group, but lets you receive individual results
// | Start | // as tasks complete — one at a time:
// +---------+
// / \
// / \
// +---------+ +---------+
// | Foo | | Bar |
// +---------+ +---------+
// \ /
// \ /
// +---------+
// | End |
// +---------+
// //
// We can express this in Zig like so: // const Race = std.Io.Select(union(enum) {
// fast: u32,
// slow: u32,
// });
// //
// fn foo() u32 { ... } // var buffer: [2]Race.Union = undefined;
// fn bar() u32 { ... } // var sel = Race.init(io, &buffer);
// //
// // Start // sel.async(.fast, fastFn, .{io});
// sel.async(.slow, slowFn, .{io});
// //
// var foo_frame = async foo(); // const winner = try sel.await(); // returns first completed
// var bar_frame = async bar(); // switch (winner) {
// .fast => |val| ...,
// .slow => |val| ...,
// }
// sel.cancelDiscard(); // cancel remaining, discard results
// //
// var foo_value = await foo_frame; // The buffer must be large enough for all tasks that might
// var bar_value = await bar_frame; // complete before you call cancelDiscard().
// //
// // End // Fix this program to receive the winner of the race.
// //
// Please await TWO page titles! const std = @import("std");
// const print = std.debug.print;
const print = @import("std").debug.print;
pub fn main() void { const RaceResult = std.Io.Select(union(enum) {
var com_frame = async getPageTitle("http://example.com"); hare: []const u8,
var org_frame = async getPageTitle("http://example.org"); tortoise: []const u8,
});
var com_title = com_frame; pub fn main(init: std.process.Init) !void {
var org_title = org_frame; const io = init.io;
print(".com: {s}, .org: {s}.\n", .{ com_title, org_title }); var buffer: [2]RaceResult.Union = undefined;
var sel = RaceResult.init(io, &buffer);
sel.async(.hare, runHare, .{io});
sel.async(.tortoise, runTortoise, .{io});
// Wait for the first finisher.
// What Select method returns the first completed result?
const winner = ???;
switch (winner) {
.hare => |msg| print("Hare: {s}\n", .{msg}),
.tortoise => |msg| print("Tortoise: {s}\n", .{msg}),
}
// Clean up the loser — we don't need their result.
sel.cancelDiscard();
} }
fn getPageTitle(url: []const u8) []const u8 { fn runHare(io: std.Io) []const u8 {
// Please PRETEND this is actually making a network request. // The hare is fast — only 1 second!
_ = url; io.sleep(std.Io.Duration.fromSeconds(1), .awake) catch return "I got canceled!";
return "Example Title"; return "I'm fast!";
}
fn runTortoise(io: std.Io) []const u8 {
// The tortoise is slow — 10 seconds.
io.sleep(std.Io.Duration.fromSeconds(10), .awake) catch return "I got canceled!";
return "Slow and steady...";
} }

View File

@@ -0,0 +1,11 @@
--- exercises/089_async6.zig 2026-04-02 10:25:34.016616118 +0200
+++ answers/089_async6.zig 2026-04-02 10:27:48.827144051 +0200
@@ -47,7 +47,7 @@
// Wait for the first finisher.
// What Select method returns the first completed result?
- const winner = ???;
+ const winner = try sel.await();
switch (winner) {
.hare => |msg| print("Hare: {s}\n", .{msg}),