【问题标题】:Two independent async loops in PythonPython中的两个独立异步循环
【发布时间】:2016-12-30 15:24:42
【问题描述】:

使用async/await在Python中执行两个并行运行的异步循环的好方法是什么?

我考虑过类似下面的代码,但不知道在这种特殊情况下如何使用async/await/EventLoop

import asyncio

my_list = []

def notify():
    length = len(my_list)
    print("List has changed!", length)

async def append_task():
    while True:
        time.sleep(1)
        await my_list.append(random.random())
        notify()

async def pop_task():
    while True:
        time.sleep(1.8)
        await my_list.pop()
        notify()

loop = asyncio.get_event_loop()
loop.create_task(append_task())
loop.create_task(pop_task())
loop.run_forever()

预期输出:

$ python prog.py
List has changed! 1 # after 1sec
List has changed! 0 # after 1.8sec
List has changed! 1 # after 2sec
List has changed! 2 # after 3sec
List has changed! 1 # after 3.6sec
List has changed! 2 # after 4sec
List has changed! 3 # after 5sec
List has changed! 2 # after 5.4sec

【问题讨论】:

  • 那么你得到的是什么输出呢? BaseEventLoop 不是具体的循环实现;使用asyncio.get_event_loop() 为您的平台获取具体循环。
  • 另外,list 操作不可等待。 time.sleep() 不会屈服于其他协程。

标签: python python-3.x asynchronous python-asyncio event-loop


【解决方案1】:

这很好用:

注意:您想等待快速的非 io 绑定操作(list.appendlist.pop 甚至都不是协程);你可以做的是awaitasyncio.sleep(...)(这是一个协程,并让控制权返回给调用者):

import asyncio
import random

my_list = []


def notify():
    length = len(my_list)
    print("List has changed!", length)

async def append_task():
    while True:
        await asyncio.sleep(1)
        my_list.append(random.random())
        notify()

async def pop_task():
    while True:
        await asyncio.sleep(1.8)
        my_list.pop()
        notify()


loop = asyncio.get_event_loop()
cors = asyncio.wait([append_task(), pop_task()])
loop.run_until_complete(cors)

time.sleep 本身处于阻塞状态,不能很好地与await 配合使用。

【讨论】:

  • 如果我有阻塞函数(例如 time.sleep()),你能解释一下该怎么做吗?所有示例都使用这个 asyncio.sleep(),但我有实际的长计算(或 i/o 绑定的东西),我不清楚如何包装它以便这个示例可以工作。非常感谢。
  • @Fab:asyncio 对 CPU 绑定功能没有帮助。如果你的 i/o 绑定的东西不是建立在 asyncio 上的,它也不会工作(这就是为什么 time.sleep() 不工作,但 asyncio.sleep() 工作。)你需要调用协程来产生程序流回到调用者从异步循环中受益。
  • 非常感谢,hiro。这大大清除了事情。那我找错地方了!
  • Asyncio 在 2.7 上不可用。
  • @rbonallo 这是真的。但由于问题是关于asyncio,它是关于python 3。或者你的意思是什么?
【解决方案2】:

列表对象没有可等待操作,它们也不需要,因为没有 I/O 或其他可以异步处理的延迟。

您还想使用asyncio.sleep(),而不是time.sleep();后者阻塞

以下工作正常;我在notify 中添加了时间戳以更好地展示这一点:

from datetime import datetime
# ...

start = datetime.now()
def notify():
    length = len(my_list)
    print("t: {:.1f}, List has changed! {}".format(
        (datetime.now() - start).total_seconds(), length))

async def append_task():
    while True:
        await asyncio.sleep(1)
        my_list.append(random.random())
        notify()

async def pop_task():
    while True:
        await asyncio.sleep(1.8)
        my_list.pop()
        notify()

请注意,我们在asyncio.sleep() 调用中使用await;这提供了一个点,您的协程(cooperative 例程)将控制权交给另一个例程。

这会产生:

$ python asyncio_demo.py
t: 1.0, List has changed! 1
t: 1.8, List has changed! 0
t: 2.0, List has changed! 1
t: 3.0, List has changed! 2
t: 3.6, List has changed! 1
t: 4.0, List has changed! 2
t: 5.0, List has changed! 3
t: 5.4, List has changed! 2
t: 6.0, List has changed! 3

【讨论】:

    猜你喜欢
    • 2018-09-18
    • 2015-02-05
    • 1970-01-01
    • 1970-01-01
    • 2018-08-03
    • 1970-01-01
    • 2018-10-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多