使用标准输入时,Python事件循环无法正常工作
问题描述
我正在试着理解Python的异步操作。我写这段代码只是为了演示清楚概念。
import asyncio
import threading
async def printer(b, a):
print(b)
await asyncio.sleep(5)
print(a)
def loop_runner(loop):
print('[RUNNING LOOP]')
loop.run_forever()
if __name__ == '__main__':
event_loop = asyncio.get_event_loop()
# run_forever() is blocking. running it from separate thread
loop_thread = threading.Thread(target=loop_runner, args=(event_loop,))
loop_thread.start()
while True:
before, after = input('Before :'), input('After :')
event_loop.create_task(printer(before, after))
我从单独的线程运行事件循环,并尝试在运行时创建循环中的任务。但是我不明白为什么这个代码不起作用。它接受输入,但随后转到下一迭代,而不打印printer
函数中的任何内容。
令人惊讶的是,如果我不从stdin
接受输入,而只是使用这样的硬编码消息
messages = [('Hello', 'world'), ('Foo', 'bar'), ('Alice', 'Bob')]
for message in messages:
before, after = message
coroutine = printer(f'[ITERATION] {count} [MESSAGE] {before}', f'[ITERATION] {count} [MESSAGE] {after}')
event_loop.create_task(coroutine)
count += 1
一切都运行得很好。输出
[RUNNING LOOP]
[ITERATION] 0 [MESSAGE] Hello
[ITERATION] 1 [MESSAGE] Foo
[ITERATION] 2 [MESSAGE] Alice
[ITERATION] 0 [MESSAGE] world
[ITERATION] 1 [MESSAGE] bar
[ITERATION] 2 [MESSAGE] Bob
请使用input
解决方案
您在第一次设置中使用异步不正确。您应该不需要将其与线程模块一起插入。
我推荐的设置是创建一个异步函数main,它包含一个无限循环,您可以在其中请求输入和创建任务。然后,您可以在声明完事件循环之后从事件循环中运行Main。 请注意,在上面的设置中,等待您在Main内部创建的任务是可选的;因为保证stdout由内核同步(我有70%的把握这是真的),您可以一次有任意多的任务运行Print()。但是,如果您确实在等待任务,则在用户尝试输入时,您的程序将不会打印输出;它将调用Printer(),该函数首先写入标准输出,并且仅在Printer()完成后才请求下一组输入。希望这回答了您的问题。请参阅下面的文档作为附加资源。
https://docs.python.org/3/library/asyncio-task.html
相关文章