python - 从 asyncio.Protocol.data_received 调用协程

标签 python python-asyncio

这类似于 Calling coroutines in asyncio.Protocol.data_received但我认为这需要一个新问题。

我有一个像这样设置的简单服务器

loop.create_unix_server(lambda: protocol, path=serverSocket)

如果我这样做,它工作正常

 def data_received(self, data):
    data = b'data reply'
    self.send(data)

我的客户得到回复。但我无法让它与任何类型的 asyncio 调用一起工作。我尝试了以下所有方法,但均无效。

@asyncio.coroutine
def go(self):
    yield from asyncio.sleep(1, result = b'data reply')

def data_received(self, data):
    print('Data Received', flush=True)

    task = asyncio.get_event_loop().create_task(self.go())
    data = yield from asyncio.wait_for(task,10)
    self.send(data)

那一个挂了,什么也没打印(如果我用 @asyncio.coroutine 修饰 data_received,我知道那不是 yield from)好的,我在 yield 中使用 yield data_received 不正确。

如果我尝试一个新的事件循环,如下所示,它将卡在 run_until_complete

    loop = asyncio.new_event_loop()
    task = loop.create_task(self.go())
    loop.run_until_complete(task)
    data = task.result()
    self.send(data)

如果我使用 Future,它也会卡在 run_until_complete

@asyncio.coroutine
def go(self, future):
    yield from asyncio.sleep(1)
    future.set_result(b'data reply')

def data_received(self, data):
    print('Data Received', flush=True)

    loop = asyncio.new_event_loop()
    future = asyncio.Future(loop=loop)
    asyncio.async(self.go(future))
    loop.run_until_complete(future)
    data = future.result()
    self.send(data)

下面的代码接近了,但是它立即返回并且结果是 asyncio.coroutines.CoroWrapper 类型,这意味着 wait_for 行立即返回了未完成的任务?

@asyncio.coroutine
def go(self):
    return(yield from asyncio.sleep(3, result = b'data reply'))

@asyncio.coroutine
def go2(self):
    task = asyncio.get_event_loop().create_task(self.go())
    res = yield from asyncio.wait_for(task, 10)
    return result

def data_received(self, data):
    print('Data Received', flush=True)

    data = self.go2()
    self.send(data)

我真的有点卡住了,希望能得到一些关于要看什么的指示。

最佳答案

您需要将协程添加到事件循环中,然后使用 Future.add_done_callback在协程完成时处理结果:

@asyncio.coroutine
def go(self):
    return(yield from asyncio.sleep(3, result = b'data reply'))

def data_received(self, data):
    print('Data Received', flush=True)

    task = asyncio.async(self.go()) # or asyncio.get_event_loop().create_task()
    task.add_done_callback(self.handle_go_result)

def handle_go_result(self, task):
    data = task.result()
    self.send(data)

直接在 data_received 中调用协程是不允许的,因为调用者不会尝试 yield from 它,并创建/运行一个新的data_received 内部的事件循环将始终阻塞主事件循环,直到内部事件循环完成其工作。

您只想使用主事件循环 (asyncio.async/loop.create_task()) 安排一些工作,并安排回调在工作时运行完成(add_done_callback)。

关于python - 从 asyncio.Protocol.data_received 调用协程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29126340/

相关文章:

python - 哪种类型提示表示属性不能为 None?

python - 在类内打开文件

python - 按顺序使用 Python 的 asyncio 获取数据

python - 在不中断程序执行的情况下获取用户输入

Python 从普通函数调用协程

python - 我的 Python3 HTTP 头解析代码可以吗?

python - 在 Python 中使用 XGboost_Regressor 可获得非常好的训练性能但预测效果较差

python - 在 Python 中包装多行字符串(保留现有的换行符)?

python-3.x - python asyncio和错误处理

python - 如何等待 python 中的任务列表?