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的有效语法是什么-我也在讨论这个问题