从另一个线程调度asyncio协同程序

时间:2016-06-15 16:44:18

标签: python multithreading python-3.x python-asyncio

我尝试使用create_task()从另一个线程安排asyncio协同程序。问题是没有调用协程,至少在合理的时间内没有调用协程。

是否有办法唤醒事件循环或至少指定更短的超时?

#!/usr/bin/python3

import asyncio, threading

event_loop = None

@asyncio.coroutine
def coroutine():
    print("coroutine called")

def scheduler():
    print("scheduling...")
    event_loop.create_task(coroutine())
    threading.Timer(2, scheduler).start()

def main():
    global event_loop

    threading.Timer(2, scheduler).start()

    event_loop = asyncio.new_event_loop()
    asyncio.set_event_loop(event_loop)
    event_loop.run_forever()

main()

输出:

scheduling...
scheduling...
scheduling...
scheduling...

2 个答案:

答案 0 :(得分:7)

根据Task的文档,“这个类不是线程安全的”。因此,预计从另一个线程调度不会起作用。

我根据这里的答案和评论找到了两个解决方案。

  1. @ wind85回答:用create_task电话直接替换asyncio.run_coroutine_threadsafe(coroutine(), event_loop)线路电话。需要Python 3.5.1。

  2. 使用call_soon_threadsafe来安排回调,然后创建任务:

    def do_create_task():
        eventLoop.create_task(coroutine())
    
    def scheduler():
        eventLoop.call_soon_threadsafe(do_create_task)
    

答案 1 :(得分:3)

这里我们去做这个shuold的工作。这是一个港口。尝试一下,因为我有最新版本,我无法向你保证它会起作用。

#!/usr/bin/python3
import concurrent.futures 
import threading, asyncio
from asyncio import coroutines, futures

def run_coroutine_threadsafe_my(coro, loop):
    """Submit a coroutine object to a given event loop.
        Return a concurrent.futures.Future to access the result.
    """
    if not coroutines.iscoroutine(coro):
        raise TypeError('A coroutine object is required')
    future = concurrent.futures.Future()

    def callback():
        try:
            futures._chain_future(asyncio.ensure_future(coro, loop=loop), future)
        except Exception as exc:
            if future.set_running_or_notify_cancel():
                future.set_exception(exc)
            raise

    loop.call_soon_threadsafe(callback)
    return future




event_loop = None

@asyncio.coroutine
async def coro():
    print("coroutine called")

def scheduler():
    print("scheduling...")
    run_coroutine_threadsafe_my(coro(),event_loop)
    threading.Timer(2, scheduler).start()

def main():
    global event_loop

    threading.Timer(2, scheduler).start()

    event_loop = asyncio.new_event_loop()
    asyncio.set_event_loop(event_loop)
    event_loop.run_forever()

main()