1

I'm creating a programming language (a bytecode interpreter). It has enough features already that make it useful. But now I want to implement asynchronous programming as well. I have been researching about this topic alot on the internet but couldn't find anything useful.Even if I do find something it's about using asyncio not about implementing it.If there is something about implementation it is too language specific. My language supports functions and coroutines.

Coroutine Syntax:

function coro()
{
  yield 1
  yield 2
  return 3 # finally return 3
}
var obj = coro()
println(obj.resume()) #1
println(obj.resume()) #2
println(obj.resume()) #3
println(obj.isAlive()) # false

The question is how would I go from coroutines to supporting asynchronous programming. I have heard of something called the event loop and I saw someone writing it in PyCon YouTube video. If I were to write his code's equivalent in my language that would be:

function coro()
{
  yield 1
  yield 2
  return 3
}
function coro1()
{
  println("here")
  yield 10
  println("here again")
  return 20
}
#create an array of tasks(or queue)
var tasks = [coro(),coro(),coro1()]
while(len(tasks)!=0)
{ 
  var curr = tasks[0]
  #run the task
  curr()
  if(curr.isAlive()) #not finished
    tasks.push(curr)
}

Is that it? Is that what asynchronous programming is all about?Creating coroutine objects,pushing them onto a queue and running them one by one? I know it's cooperative multitasking because coroutines are voluntarily suspending themselves.Also once a IO operation has started, how can a coroutine suspend itself in such a way that the IO operation continues running in the background?

shahryar
  • 83
  • 5
  • Does that help? https://stackoverflow.com/questions/49005651/how-does-asyncio-actually-work/51116910#51116910 – Bharel Jan 18 '23 at 12:26

1 Answers1

0

Yes - that is the idea. What I/O code does is that the framework also needs a low-level way of doing the co-routines implementing the tradicional callbacks - so, for users, a async I/O call is exposed as a normal co-routine, but for the event loop, instead of switching into a co-routine, it is run as a normal function call, and registers a callback with the Operating System to be run when the I/O is complete: that callack then finishes emulating the co-routine behavior with the asyncio loop - which will return the callback value to awaiting co-routines in the tasks' call stack.

You can see bellow the implementation of Python's "asyncio.sleep" primitive: it creates a "Future"object, and sets, as a callback with the needed delay, a function that will just mark itself as done - then it (the sleep code), awaits this future: this wraps a tradicional "co-routine" in a "resolve when the callback is done" computation. For traditional I/O, the OS must have a way to provide a callback when the result is available and ready to be consumed - the async I/O libraries perform the wrappings so these I/O operations can be performed as co-routine.

From cpython Lib/asyncio/tasks.py :

async def sleep(delay, result=None):
    """Coroutine that completes after a given time (in seconds)."""
    if delay <= 0:
        await __sleep0()
        return result

    loop = events.get_running_loop()
    future = loop.create_future()
    h = loop.call_later(delay,
                        futures._set_result_unless_cancelled,
                        future, result)
    try:
        return await future
    finally:
        h.cancel()
jsbueno
  • 99,910
  • 10
  • 151
  • 209