Python中的多线程asyncio

时间:2016-03-31 14:30:04

标签: multithreading python-asyncio

我目前正在使用Python 3.5中的asyncio开始我的第一步,并且有一个问题困扰着我。显然我还没有完全理解协程......

以下是我正在做的简化版本。

在我的课程中,我有一个open()方法,可以创建一个新线程。在该线程中,我创建了一个新的事件循环和一些主机的套接字连接。然后我让循环永远运行。

def open(self):
    # create thread
    self.thread = threading.Thread(target=self._thread)
    self.thread.start()
    # wait for connection
    while self.protocol is None:
        time.sleep(0.1)

def _thread(self):
    # create loop, connection and run forever
    self.loop = asyncio.new_event_loop()
    coro = self.loop.create_connection(lambda: MyProtocol(self.loop),
                                       'somehost.com', 1234)
    self.loop.run_until_complete(coro)
    self.loop.run_forever()

现在停止连接非常简单,我只是停止主线程的循环:

loop.call_soon_threadsafe(loop.stop)

不幸的是我需要做一些清理工作,特别是在断开与服务器的连接之前我需要清空一个队列。所以我尝试了MyProtocol中的这个stop()方法:

class MyProtocol(asyncio.Protocol):
    def __init__(self, loop):
        self._loop = loop
        self._queue = []

    async def stop(self):
        # wait for all queues to empty
        while self._queue:
            await asyncio.sleep(0.1)
        # disconnect
        self.close()
        self._loop.stop()

队列从协议的data_received()方法中清空,所以我只想等待使用带有asyncio.sleep()调用的while循环。然后我关闭连接并停止循环。

但是如何从主线程调用此方法并等待它? 我尝试了以下方法,但它们似乎都没有工作(协议是当前使用的MyProtocol实例):

loop.call_soon_threadsafe(protocol.stop)
loop.call_soon_threadsafe(functools.partial(asyncio.ensure_future, protocol.stop(), loop=loop))
asyncio.ensure_future(protocol.stop(), loop=loop)

有人可以帮我吗?谢谢!

1 个答案:

答案 0 :(得分:6)

基本上你想在不同线程的循环上安排协同程序。您可以使用run_coroutine_threadsafe

future = asyncio.run_coroutine_threadsafe(protocol.stop, loop=loop)
future.result()  # wait for results

https://stackoverflow.com/a/32084907/681044

中的旧样式async
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())