#When calling function using async, does the function run always on the main thread?
1 messages · Page 1 of 1 (latest)
Zig won't do multithreading unless you explicitly tell it to
Async effectively generates a state machine - whenever the function suspends, it saves its current state and jumps back to that point when it's resumed
Depending on what you're using async for, the event loop may decide to move suspended functions to other threads, however
But that's not anything to do with the actual language async
This is a decent intro to async in Zig: https://kristoff.it/blog/zig-colorblind-async-await/
I think calling it a state machine is a bit confusing. IIUC The only state in an async functions that is distinct from a normal function is storing the instruction pointer (and even normal functions kinda do that under the hood)
Async means: create the memory space that a normal function needs, but at a given memory location that is not necessarily on the stack, and allow the function to "put a pin on its action" and temporarily suspend itself. Then keep track of the {memory location, IP} pair as a "future" each time you suspend. Something external would needs to resume it in this case. (This is why I'm dissatisfied with the name "async"). You could write an async function with no suspension points that is basically a really inconvenient to execute normal function.
You're welcome to manually manipulate async functions, and that is useful thing to do, but the language proper doesn't provide you with any conveniences. However, the stdlib does. This is like how zig the language "doesn't have any allocators" but zigs stdlib has more allocators than just about any other LLL
Thanks @silver crow @acoustic drift! Now it's a lot more clear. So, as I understand if I want multi-threading, the official way to do it is using this - https://github.com/ziglang/zig/blob/master/lib/std/Thread.zig ?
Yes, use that for simple multithreading, and you don't have to muck around with async
Fair, maybe describing it as a state machine is confusing. That is how it's implemented though I believe
It's compiled down to a state machine (think "switch case") where each suspension point creates a new "case" in the state machine. The concept of "instruction pointer" doesn't map too well atm because it still uses the OS thread stack + cpu instruction pointer when executing each of it's "case"s.
The name "async" means that the function can execute concurrently/non-synchronously (w.r.t its completion) with other (normal or async) functions; Synchronous functions complete when they return to the caller, which isn't guaranteed to (but can) be the case for async functions.
When interacting with @Frame(func), you're manipulating a (potentially "running") instance of that function rather than the function itself, if that makes any sense. Some stdlib functions like std.event.Loop.runDetached simplify these interactions.
async code work just like this: #programming-discussion message
(w.r.t its completion)
Yeah, that's what I don't like about the name. its execution is run exclusively on whatever the thread called it, and as you can see from the head of this thread that fact has already caused confusion, but I don't want to bikeshed too much 😄
oh really, it compiles to a duff's device basically? huh. I still don't like to think of that as a "state machine" tbh I never liked calling async stuff state machines because at some level everything reduces to a state machine. =/
this really good example
yes, if you scroll up to see how long I've been asking for this, due to my own misunderstanding.... 😅
reading through, its kinda unfortunate the builtin/type is called @Frame() cuz it makes you think "stack frame" from stackful coroutines (i.e. fibers)
but it is an activation frame, is it not
Async functions can be moved between threads, they don't have to run exclusively on the thread that started them
What does "activation frame" refer to in this case? All I see online are like a stack with a return address, params/locals, etc. (zig async Frames aren't a stack)
sorry, activation record. the call stack is the designated region of stack-allocated activation records. i don't know why it's never stack record or activation frame, but whatever. it doesn't matter whether it's on the stack or not, a function call is an object.
you might as well call it a frame, because it serves the same purpose of tracking the call's state
yea, but then one could think "stack frame", then infer that it works like that and try to manipulate/inspect it as such
the only other term i can think of is Thunk