After the other forum post wanting to efficiently execute a proc at a delayed time I figured I might as well start learning a bit more about async. I have a few rather beginner questions concerning async in nim. For now I just want to explore a bit based on the following code-snippet for which I have a couple questions:
import std/[asyncdispatch]
let echoMe: Callback = proc(fd: AsyncFD): bool =
echo "Me"
return true
addTimer(100, true, echoMe)
poll()
Then as a general question:
So basically if I want to have asyncdispatch working continuosly throughout my application and not think about the eventloop, I need to run:
proc runForever*() =
while true:
poll()
Given it's a while-true loop, isn't this essentially blocking a thread with polls to a task-queue until a task is in there and then that thread works on that? Is that okay or is that a bad idea?
What is AsyncFD in terms of meaning? (I'm aware it's a distinct int32, but what does that mean?)
FD is abbreviation of file descriptor, on Windows it's called Handle. FD/Handle is basically just and object and with AsyncFD meaning can be applied for asynchronous operation. On Windows it's the Handle that created with Ex variants of IO operations, like ReadFileEx, CreateFileEx etc. On Linux with epoll it's fd that's returned from epoll_create.
Why does a Callback need to return a boolean? What does it mean to return true/false?
Not necessarily but in your specific example, from the doc, addTimer need to return boolean to identify whether it's running once or periodically.
Why does the callback above only execute echoMe once? Shouldn't it do that 5 times given that poll lasts 500ms and the "true" parameter of addTimer means it gets repeated?
poll only waiting "until" 500 ms, if timeout, throw ValueError, since addTimer expired already in 100 ms, so it doesn't need to waste 400 ms. Try changing to runForever() you'll get the uncaught ValueError (idk if this intended or bug).
Is there any way to do this in a way that means I don't have to call poll because the sources I'm skimming through atm make it sound like that would be the task of a runtime to do manage that sort of thing
Directly or indirectly? Indirectly to avoid calling poll, you can just runForever it. To Directly avoiding, you can't because you need to yield the control to another operations/values in queue.
What's the difference to the prior approach and this?
import std/asyncdispatch
proc afterX(wait: int) {.async.} =
await sleepAsync(wait)
echo "Stuff Happened"
waitFor afterX(400)
Are they both basically the same with the waitFor just disguising a poll-loop ?
I think I just had somewhat of a lightbulb moment:
Nim has await and waitFor, while JS only has await - which is equivalent to nim's await. JS does not have an equivalent to waitFor.
Is that because in JS basically everything gets executed within an event-loop?
And you just don't notice it/ it gets hidden from you because JS doesn't let you interact with resources outside of the context of an event-loop, so everything you're doing essentially runs within a gargantuan async function within which you can call await as you please ?
Meanwhile whatever code calls an equivalent to waitFor is what's thus running the JS runtime?
Again you're pretty much spot on. In JS and many other languages which implements the async/await pattern the event loop is hidden away from you, run by a part of the runtime for the language. Nim however doesn't really have async/await built in, the language just provides the building blocks, and the rest is supplied in a library.
To answer your questions from earlier: