-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Closed as not planned
Closed as not planned
Copy link
Labels
proposalThis issue suggests modifications. If it also has the "accepted" label then it is planned.This issue suggests modifications. If it also has the "accepted" label then it is planned.
Milestone
Description
I thought I had already proposed this but I could not find it. This depends on the , which is related to #3164 but I will open an explicit proposal for it.cancel proposal being accepted
There is one thing missing with zig's async / await features which is the ability to respond to the first completed function. Here's a use case:
fn httpRequestWithTimeout(url: []const, timeout_duration: u64) !Response {
var request_tok = CancelToken{};
var request = async httpRequest(url, &request_tok);
defer request_tok.cancel(&request);
var timeout_tok = CancelToken{};
var timeout = async sleep(timeout_duration, &timeout_tok);
defer timeout_tok.cancel(&timeout);
select {
request => |result| {
request_tok.awaited = true;
return result;
},
timeout => {
timeout_tok.awaited = true;
return error.TimedOut;
},
}
}Here's a more complicated example, which shows how select also supports arrays of frames:
fn httpRequestWithMirrors(mirrors: []const []const u8) !Request {
const frames = try allocator.alloc(@Frame(httpRequest), mirrors.len);
defer allocator.free(frames);
const cancel_tokens = try allocator.alloc(CancelToken, mirrors.len);
defer allocator.free(cancel_tokens);
for (frames) |*frame, i| {
cancel_tokens[i] = CancelToken{};
frame.* = async httpRequest(mirrors[i], &cancel_token[i]);
}
defer for (cancel_tokens) |*tok, i| tok.cancel(&frames[i]);
var in_flight_count: usize = mirrors.len;
while (true) {
select {
frames => |result, i| {
cancel_tokens[i].awaited = true;
if (result) |payload| {
return payload;
} else |err| {
in_flight_count -= 1;
if (in_flight_count == 0)
return err;
}
},
}
}
}Here's another use case:
Lines 68 to 86 in 9b788b7
| /// Add a frame to the Batch. If all jobs are in-flight, then this function | |
| /// waits until one completes. | |
| /// This function is *not* thread-safe. It must be called from one thread at | |
| /// a time, however, it need not be the same thread. | |
| /// TODO: "select" language feature to use the next available slot, rather than | |
| /// awaiting the next index. | |
| pub fn add(self: *Self, frame: anyframe->Result) void { | |
| const job = &self.jobs[self.next_job_index]; | |
| self.next_job_index = (self.next_job_index + 1) % max_jobs; | |
| if (job.frame) |existing| { | |
| job.result = if (async_ok) await existing else noasync await existing; | |
| if (CollectedResult != void) { | |
| job.result catch |err| { | |
| self.collected_result = err; | |
| }; | |
| } | |
| } | |
| job.frame = frame; | |
| } |
As an alternative syntax, we could replace select with await. Since only labeled blocks can return values, await { is unambiguously the "select" form of await.
Soupertonic, mogud, deingithub, euantorano, SpexGuy and 29 more
Metadata
Metadata
Assignees
Labels
proposalThis issue suggests modifications. If it also has the "accepted" label then it is planned.This issue suggests modifications. If it also has the "accepted" label then it is planned.