overexchange
overexchange

Reputation: 1

How python asyncIO, suspend & resume the task?

A style of programming in which task release the CPU during waiting periods, so that other tasks can use it.

To introduce an async task,

Wrote event scheduler, but stuck in enabling an async task. Assume the task being IO bound. Scheduler does not get CPU slice, amidst task execution, because task gets executed synchronously.


A task(bar) in python, becomes async task(capable to suspend & resume), when task uses async, await keywords with ayncio.onSomeIO capable wait,

async def bar():
   await asyncio.onSomeIO()

Question:

How asyncio package enables bar, to be an async task, with these keywords, under the hood? Does each task get launched on separate thread?

Upvotes: 2

Views: 2780

Answers (1)

Mikhail Gerasimov
Mikhail Gerasimov

Reputation: 39546

Does each task get launched on separate thread?

No, usually asyncio runs in single thread.

How asyncio package enables bar, to be an async task, with these keywords, under the hood?

When you define function as async this function becomes generator what allows to execute it "by steps" using __next__() method. await - is yield (yield from actually) point where execution flow returns to global event loop that manages executing of all coroutines.

This simple example shows how you can switch between execution flow of different generators:

def task(i):
    yield 1
    print('task {}: step 1'.format(i))
    yield 2
    print('task {}: step 2'.format(i))


tasks = [
    task(1),
    task(2),
    task(3),
]


def execute_tasks(tasks):
    i = 0
    finished = []
    while True:
        # start executing tasks:
        try:
            tasks[i].__next__()
        except StopIteration:
            finished.append(i)
        # check if any task unfinished:
        if len(finished) == len(tasks):
            return
        # move to next unfinished task:
        while True:
            i += 1
            if i > len(tasks) - 1:
                i = 0
            if not i in finished:
                break


if __name__ == '__main__':
    execute_tasks(tasks)

Output:

task 1: step 1
task 2: step 1
task 3: step 1
task 1: step 2
task 2: step 2
task 3: step 2

asyncio of course is much more complex and allows you much more.

Probably best explanation of how you can implement coroutines using generators I saw in this PyCon 2015 video: David Beazley - Python Concurrency From the Ground Up: LIVE! (source code). You should definitely watch it if you're going implement this.

But I advice you to use asyncio instead - it already exists for you, there's no need to invent your own.

Upvotes: 4

Related Questions