为了账号安全,请及时绑定邮箱和手机立即绑定

试图用一个事件停止循环,但它没有

试图用一个事件停止循环,但它没有

慕村9548890 2021-06-06 16:35:07
据我所知,asyncio这应该只打印 0 到 4,但它会显示完整的 10 位数字。stop_loop协程不应该在我点击 5 后停止等待事件并取消循环吗?import asyncioasync def run():    for i in range(10):        if i == 5:            e.set()        print(i)async def stop_loop():    await e.wait()    l.stop()e = asyncio.Event()l = asyncio.get_event_loop()l.set_debug(True)l.create_task(stop_loop())l.create_task(run())try:    l.run_forever()finally:    l.close()输出是machine:programs user$ python3 conditional_stop.py 0123456789
查看完整描述

1 回答

?
MM们

TA贡献1886条经验 获得超2个赞

asyncio通过在作为协程实现的任务之间切换来工作。一个协同程序是一个合作的程序,在协程自愿放弃控制权曾经在一段时间,以让该asyncio事件循环切换到另一个任务。这与线程不同,在线程中每个任务可以并且将被调度程序“随意”中断。


并且协程每次await在另一个协程上使用时都会放弃控制,通常是在涉及某些 I/O 的地方。I/O 很慢,asyncio事件循环负责监控 I/O 流的变化,以便它可以知道哪些任务准备好再次做更多的工作。


你的问题是你有一个不合作的协程:


async def run():

    for i in range(10):

        if i == 5:

            e.set()

        print(i)

该例程没有await语句,因此它永远不会放弃对事件循环的控制。不能运行其他协程。


你可以等待一个asyncio.sleep()电话:


async def run():

    for i in range(10):

        if i == 5:

            e.set()

        print(i)

        await asyncio.sleep(0.01)  # wait 1/100th of a second

另一种选择是将print(i)调用(这是一个 I/O 操作)替换为使用非阻塞输出流的调用。如果您不在 Windows 上,则可StreamWriter以为以下对象创建异步 I/O 包装器sys.stdout:


import os

import sys


async def run():

    # create an async writer for sys.stdout

    loop = asyncio.get_event_loop()

    writer_transport, writer_protocol = await loop.connect_write_pipe(

        asyncio.streams.FlowControlMixin, os.fdopen(sys.stdout.fileno(), 'wb'))

    writer = asyncio.streams.StreamWriter(

        writer_transport, writer_protocol, None, loop)


    for i in range(10):

        if i == 5:

            e.set()

        writer.write(b'%d\n' % i)

        await writer.drain()

不幸的是,尚不支持为 Windows 控制台流创建异步 I/O 流,请参阅Pyton 问题 #26832,您必须改用线程池执行程序。


请注意,甚至与后者协同程序,也不能保证该stop协程将实际运行不久后,足以e.set()被称为取消run()它读取前10名!在处理之后,循环可以自由地将控制权交还给同一个协程await writer.drain()。向sys.stdout流缓冲区写入短行很快,唯一要做.drain()的就是让写入协程有时间刷新内部传输缓冲区;sys.stdout大多数情况下直接非阻塞写入成功,这并不总是有足够的空间stop_loop()来跳入,run()协程会将其所有行都写入写入器传输。



查看完整回答
反对 回复 2021-06-16
  • 1 回答
  • 0 关注
  • 161 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信