启动异步功能而不导入asyncio包

发布于 2021-01-29 17:22:26

可以启动这样的功能

async def foo():
    while True:
        print("Hello!")

没有导入asyncio包(并获取事件循环)?

我正在寻找一种类似于Go的goroutine的原理,在该原理中,仅需go声明即可启动协程。

编辑:之所以我不导入asyncio软件包,仅仅是因为我认为应该可以在没有事件循环(明确)的情况下启动协程。我不明白为什么 异步def
和类似的语句是核心语言(甚至是语法的一部分)的一部分,而启动已创建的协程的方法仅通过包提供。

关注者
0
被浏览
50
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    当然,async无需显式使用即可启动功能asyncio。毕竟,它asyncio是用Python编写的,所以它也可以执行所有操作(尽管有时可能需要其他模块,例如selectors或者threading如果您打算同时等待外部事件,或者并行执行其他代码)。

    在这种情况下,由于您的函数await内部没有点,因此只需要按一下即可进行操作。您可以通过推协程send荷兰国际集团None到它。

    >>> foo().send(None)
    Hello!
    Hello!
    ...
    

    当然,如果您的函数(协程)yield内部包含表达式,它将在每个yield点暂停执行,并且您需要将其他值(按coro.send(value)next(gen))推入其中-
    但是您已经知道如果知道生成器的工作方式。

    import types
    
    @types.coroutine
    def bar():
        to_print = yield 'What should I print?'
        print('Result is', to_print)
        to_return = yield 'And what should I return?'
        return to_return
    
    >>> b = bar()
    >>> next(b)
    'What should I print?'
    >>> b.send('Whatever you want')
    Result is Whatever you want
    'And what should I return?'
    >>> b.send(85)
    Traceback...
    StopIteration: 85
    

    现在,如果您的函数await内部包含表达式,它将暂停对每个表达式的求值。

    async def baz():
        first_bar, second_bar = bar(), bar()
        print('Sum of two bars is', await first_bar + await second_bar)
        return 'nothing important'
    
    >>> t = baz()
    >>> t.send(None)
    'What should I print?'
    >>> t.send('something')
    Result is something
    'And what should I return?'
    >>> t.send(35)
    'What should I print?'
    >>> t.send('something else')
    Result is something else
    'And what should I return?'
    >>> t.send(21)
    Sum of two bars is 56
    Traceback...
    StopIteration: nothing important
    

    现在,所有这些.send都开始变得乏味。半自动生成它们会很好。

    import random, string
    
    def run_until_complete(t):
        prompt = t.send(None)
        try:
            while True:
                if prompt == 'What should I print?':
                    prompt = t.send(random.choice(string.ascii_uppercase))
                elif prompt == 'And what should I return?':
                    prompt = t.send(random.randint(10, 50))
                else:
                    raise ValueError(prompt)
        except StopIteration as exc:
            print(t.__name__, 'returned', exc.value)
            t.close()
    
    >>> run_until_complete(baz())
    Result is B
    Result is M
    Sum of two bars is 56
    baz returned nothing important
    

    恭喜,您刚刚编写了第一个事件循环!(没想到它会发生,是吗?;)当然,这是非常原始的:它只知道如何处理两种类型的提示,它无法t生成与之同时运行的其他协程,并且由random生成器伪造事件。

    (实际上,如果您想了解一点:我们在手动操作之上所做的事情, 可以称为事件循环:Python
    REPL将提示打印到控制台窗口,并且依靠您通过在其中键入事件来提供事件t.send(whatever)。 :)

    asyncio只是上述内容的一个非常广泛的变体:提示符被Futures取代,多个协程保留在队列中,因此每个协程最终轮流使用,事件更加丰富,包括网络/套接字通信,文件系统读/写,信号处理,线程/进程副执行等。但是基本思想仍然是相同的:您抓取一些协程,将它们从空中传送到另一个空中,直到它们全部升起,然后将它们杂耍起来StopIteration。当所有协程无关时,您将前往外部世界并获取一些其他事件,让它们继续咀嚼。

    我希望现在一切都清楚了。:-)



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看