Python 将异步IO任务发送到在其他线程中运行的循环
如何异步插入要在另一个线程中运行的Python 将异步IO任务发送到在其他线程中运行的循环,python,python-asyncio,Python,Python Asyncio,如何异步插入要在另一个线程中运行的asyncio事件循环中运行的任务 我的动机是在解释器中支持交互式异步工作负载。我无法阻止主REPL线程 例子 我目前有缺陷的理解是,以下方法应该有效。为什么不呢?实现上述目标的更好方法是什么 import asyncio from threading import Thread loop = asyncio.new_event_loop() def f(loop): asyncio.set_event_loop(loop) loop.run
asyncio
事件循环中运行的任务
我的动机是在解释器中支持交互式异步工作负载。我无法阻止主REPL线程
例子
我目前有缺陷的理解是,以下方法应该有效。为什么不呢?实现上述目标的更好方法是什么
import asyncio
from threading import Thread
loop = asyncio.new_event_loop()
def f(loop):
asyncio.set_event_loop(loop)
loop.run_forever()
t = Thread(target=f, args=(loop,))
t.start()
@asyncio.coroutine
def g():
yield from asyncio.sleep(1)
print('Hello, world!')
asyncio.async(g(), loop=loop)
您必须使用
call\u soon\u threadsafe
计划来自不同线程的回调:
import asyncio
from threading import Thread
loop = asyncio.new_event_loop()
def f(loop):
asyncio.set_event_loop(loop)
loop.run_forever()
t = Thread(target=f, args=(loop,))
t.start()
@asyncio.coroutine
def g():
yield from asyncio.sleep(1)
print('Hello, world!')
loop.call_soon_threadsafe(asyncio.async, g())
有关更多信息,请参阅
编辑:支持异步工作负载的解释器示例
# vim: filetype=python3 tabstop=2 expandtab
import asyncio as aio
import random
@aio.coroutine
def async_eval(input_, sec):
yield from aio.sleep(sec)
print("")
try:
result = eval(input_)
except Exception as e:
print("< {!r} does not compute >".format(input_))
else:
print("< {!r} = {} >".format(input_, result))
@aio.coroutine
def main(loop):
while True:
input_ = yield from loop.run_in_executor(None, input, "> ")
if input_ == "quit":
break
elif input_ == "":
continue
else:
sec = random.uniform(5, 10)
print("< {!r} scheduled for execution in {:.02} sec>".format(input_, sec))
aio.async(async_eval(input_, sec))
loop = aio.get_event_loop()
loop.run_until_complete(main(loop))
loop.close()
#vim:filetype=python3 tabstop=2 expandtab
将异步IO导入为aio
随机输入
@共同程序
def异步评估(输入,秒):
人工睡眠收益率(秒)
打印(“”)
尝试:
结果=评估(输入)
例外情况除外,如e:
打印(“<{!r}不计算>”。格式(输入)
其他:
打印(“<{!r}={}>”。格式(输入,结果))
@共同程序
def主(回路):
尽管如此:
输入=从循环中产生。在执行器中运行(无,输入“>”)
如果输入=“退出”:
打破
elif输入\==“”:
持续
其他:
秒=随机均匀(5,10)
打印(“{!r}计划在{:.02}秒>”中执行。格式(输入秒))
aio.async(异步评估(输入秒))
loop=aio.get\u event\u loop()
循环。运行_直到_完成(主循环))
loop.close()
Jashandeep Sohi答案中的第一个示例在3.7+中不适用于我,并打印有关不推荐注释的警告。我把它修改成了一个运行在3.8下的东西。为了满足我的需要,我对它做了一些调整。我不熟悉Python中的多线程(但一般来说没有多线程),因此请提供任何建议、指导等:
import asyncio
from threading import Thread
loop = asyncio.new_event_loop()
running = True
def evaluate(future):
global running
stop = future.result()
if stop:
print("press enter to exit...")
running = False
def side_thread(loop):
asyncio.set_event_loop(loop)
loop.run_forever()
thread = Thread(target=side_thread, args=(loop,), daemon=True)
thread.start()
async def display(text):
await asyncio.sleep(5)
print("echo:", text)
return text == "exit"
while running:
text = input("enter text: ")
future = asyncio.run_coroutine_threadsafe(display(text), loop)
future.add_done_callback(evaluate)
print("exiting")
回声和其他输出将与提示冲突,但应足以证明其工作
我不确定的一件事是设置全局
从一个线程运行,然后从另一个线程读取。我认为GIL可能会同步线程缓存,但我希望得到确认(或不确认)。您可以尝试使用REPL--它可以与异步IO一起开箱即用。或者--它也可以在REPL中运行异步函数,因为版本7.0。有没有办法在另一个线程中运行整个python脚本。我有类似的需求,如本主题所述。很好。如果我想得到g()
的返回结果,怎么样?(如果g
实际返回了一些内容。)您可以将未来传递到g
中,并在g
中设置它的结果,然后您可以在另一个线程的另一个事件循环中从该未来产生。您也可以创建另一个协同程序,在其中从g()
产生,然后在新的协同程序上调用\u soon\u threadsafe
。理想情况下,我只需重新处理逻辑,在没有线程的情况下执行此操作。或者,即使您必须使用线程,也可以尝试使用循环。在执行器
corroutine中运行,它可以在线程中调用阻塞函数,但仍然看起来像asyncio
ish。请参阅我的编辑,了解我对使用此方法的解释器中的支持交互式异步工作负载的解释。
如果需要在另一个线程的事件循环上运行协程,请使用:asyncio.run\u协程\u threadsafe(my\u coro(param1),loop)
3.7的有效语法是什么-我也在讨论这个问题