不使用 asyncio 编写 EventLoop

Writing an EventLoop without using asyncio

我越来越熟悉 python 的 asyncio、python 中的异步编程、协程等。 我希望能够使用我自己定制的 eventloop 执行多个协同例程。

我很好奇我是否可以在完全不导入 asyncio 的情况下编写自己的 eventloop

I want to be able to executing several co-routines with my own custom made eventloop.

异步事件循环经过充分测试,可以轻松扩展以确认非异步事件。如果您描述实际用例,可能会更容易提供帮助。但是,如果您的目标是 学习 异步编程和协程,请继续阅读。

I'm curious if i can write my own eventloop without importing asyncio at all

这绝对是可能的 - 毕竟 asyncio 本身只是一个库 - 但需要一些工作才能让你的事件循环发挥作用。请参阅 David Beazley 的 this excellent talk,他在其中演示了如何在现场观众面前编写事件循环。 (不要被大卫使用旧的 yield from 语法推迟 - await 的工作方式完全相同。)

好的,所以我在某个地方找到了一个例子(抱歉,不记得在哪里,没有link),并稍微改变了一点。

eventloopco-routins 甚至没有导入 asyncio:

import datetime
import heapq
import types
import time

class Task:
    def __init__(self, wait_until, coro):
        self.coro = coro
        self.waiting_until = wait_until

    def __eq__(self, other):
        return self.waiting_until == other.waiting_until

    def __lt__(self, other):
        return self.waiting_until < other.waiting_until

class SleepingLoop:
    def __init__(self, *coros):
        self._new = coros
        self._waiting = []

    def run_until_complete(self):
        # Start all the coroutines.
        for coro in self._new:
            wait_for = coro.send(None)
            heapq.heappush(self._waiting, Task(wait_for, coro))

        # Keep running until there is no more work to do.
        while self._waiting:
            now = datetime.datetime.now()
            # Get the coroutine with the soonest resumption time.
            task = heapq.heappop(self._waiting)
            if now < task.waiting_until:
                # We're ahead of schedule; wait until it's time to resume.
                delta = task.waiting_until - now
                time.sleep(delta.total_seconds())
                now = datetime.datetime.now()
            try:
                # It's time to resume the coroutine.
                wait_until = task.coro.send(now)
                heapq.heappush(self._waiting, Task(wait_until, task.coro))
            except StopIteration:
                # The coroutine is done.
                pass


@types.coroutine
def async_sleep(seconds):
    now = datetime.datetime.now()
    wait_until = now + datetime.timedelta(seconds=seconds)
    actual = yield wait_until

    return actual - now


async def countdown(label, total_seconds_wait, *, delay=0):
    print(label, 'waiting', delay, 'seconds before starting countdown')
    delta = await async_sleep(delay)
    print(label, 'starting after waiting', delta)
    while total_seconds_wait:
        print(label, 'T-minus', total_seconds_wait)
        waited = await async_sleep(1)
        total_seconds_wait -= 1
    print(label, 'lift-off!')


def main():
    loop = SleepingLoop(countdown('A', 5, delay=0),
                        countdown('B', 3, delay=2),
                        countdown('C', 4, delay=1))
    start = datetime.datetime.now()
    loop.run_until_complete()

    print('Total elapsed time is', datetime.datetime.now() - start)



if __name__ == '__main__':
    main()