Hi,
I added async support to my pet language and after reading more about async programming, I have some questions.
Currently, in my interpreter, after every X evaluations, the interpreter will check whether there are pending futures and if yes, check their states, call the success or failure callback depending on whether the state is success or error.
This can happen at ANY time, like inside a function execution, a for loop etc. And it can cause unpredictable behavior.
However I couldn't figure out a better way. As in my language, all are evaluations - importing a module, calling a function, adding two numbers etc.
Even if the interpreter doesn't do this automatically in the middle of execution, and only check futures at the end of main script. Unpredictable behavior is inevitable because when the user uses await to wait for futures, futures created elsewhere will be checked at the same time and callbacks will be called. Means a future's callback can be invoked when least expected.
Is this something I need to worry? Or is this part of async programming and we all must live with?
I am far from an expert on this, but my understanding of nim and python async runtimes, is that task switches (check for pending future, etc) only happen when the routine that is currently running invokes await (or finishes). await explicitly pauses your routine and gives the control back to the scheduler/runtime. Your routine will continue execution sometime after whatever you are awaiting completes.
What you're implementing is closer to time-slicing in OSes, which is how OSs run multiple processes concurrently. However, when an OS does a context switch, it ensures complete isolation by saving/restoring the stack, CPU registers and whatnot.
Finally, whatever you do, concurrent programs (even in Nim or python or Go) can always lead to "unpredictable behavior" through programming errors (aka race conditions).
Is this something I need to worry? Or is this part of async programming and we all must live with?
You must live with it as far as I can tell. For a "pet" language I wouldn't add async. ;-) Just make the interpreter re-entrant instead and build some of our nice multi-threaded server software into your virtual machine.
Thank you all. I'll leave it as is. For a pet language, I want to add all features I like in other languages, plus more :-P
For the multithread support, I'm creating new VM for each thread, and use channels to communicate. Will see how it evolves as I add more use cases.