Skip to content

Instantly share code, notes, and snippets.

@ikskuh
Last active July 11, 2022 08:41
Show Gist options
  • Save ikskuh/ff534f912c5faedbbb57974317e79778 to your computer and use it in GitHub Desktop.
Save ikskuh/ff534f912c5faedbbb57974317e79778 to your computer and use it in GitHub Desktop.
Async Await in 60 LOC
const std = @import("std");
// usage:
fn asyncMain() !void {
// Start two interleaving tasks
var task_a = async waitUntilAndPrint(start + 1000, start + 1200, "task a");
var task_b = async waitUntilAndPrint(start + 500, start + 1300, "task b");
var task_c = async waitUntilAndPrint(start + 800, start + 1100, "task c");
await task_a;
await task_b;
await task_c;
}
fn waitUntilAndPrint(time1: i64, time2: i64, name: []const u8) void {
waitForTime(time1);
std.log.info("[{s}] it is now {} ms since start!", .{ name, std.time.milliTimestamp() - start });
waitForTime(time2);
std.log.info("[{s}] it is now {} ms since start!", .{ name, std.time.milliTimestamp() - start });
}
// impementation
const Task = struct { frame: anyframe, time: i64 };
const TaskList = std.TailQueue(Task);
var task_list: TaskList = .{};
var start: i64 = 0;
fn waitForTime(time: i64) void {
var task = TaskList.Node{ .data = Task{ .frame = undefined, .time = time } };
suspend {
task.data.frame = @frame();
task_list.append(&task);
}
_ = task; // keep it alive over the suspend point
}
fn isTaskReady(task: Task) bool {
return task.time <= std.time.milliTimestamp();
}
pub fn main() !void {
start = std.time.milliTimestamp();
var main_task = async asyncMain();
while (true) // this is "the event loop"
{
var node = task_list.first orelse {
// no pending tasks running anymore, stop asynchronous tasking
break;
};
while (true) {
const next = node.next;
if (isTaskReady(node.data)) { // resume condition
task_list.remove(node); // erase from the task list
resume node.data.frame; // continue execution in our task
}
node = next orelse break; // end of the list
}
}
// finalize the tasks properly (we know they finished as they are no more tasks left)
// but main might have returned a error!
try nosuspend await main_task;
}
@tjpalmer
Copy link

Unrelated to async, but Zig 0.8.0 wants me to use {s} instead of just {} for the first slot in this line:

std.log.info("[{}] it is now {} ms since start!", .{ name, std.time.milliTimestamp() - start });

Is support for plain {} in an upcoming release?

@ikskuh
Copy link
Author

ikskuh commented Jul 18, 2021

Is support for plain {} in an upcoming release?

This was removed due to being ambigious, so probably no

@tjpalmer
Copy link

Thanks for the reply, by the way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment