从asyncio.Protocol.data_received调用协同程序

Dav*_*ave 11 python python-asyncio

这类似于在asyncio.Protocol.data_received中调用协同程序,但我认为它保证了一个新问题.

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

loop.create_unix_server(lambda: protocol, path=serverSocket)
Run Code Online (Sandbox Code Playgroud)

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

 def data_received(self, data):
    data = b'data reply'
    self.send(data)
Run Code Online (Sandbox Code Playgroud)

我的客户得到答复.但我不能让它与任何类型的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)
Run Code Online (Sandbox Code Playgroud)

没有任何东西挂起并且没有打印(如果我装饰的话data_received,@asyncio.coroutine我得到的不是那个)好的,我知道使用yield in 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)
Run Code Online (Sandbox Code Playgroud)

如果我使用a 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)
Run Code Online (Sandbox Code Playgroud)

以下是关闭,但它立即返回,结果是类型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)
Run Code Online (Sandbox Code Playgroud)

我真的有点卡住了,并会欣赏一些关于要看什么的指示.

dan*_*ano 14

您需要将协程添加到事件循环中,然后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)
Run Code Online (Sandbox Code Playgroud)

直接调用协程data_received是不允许的,因为调用者不会尝试yield from它,并且在内部创建/运行新的事件循环data_received总是会阻塞主事件循环,直到内部事件循环结束工作.

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

  • Python 3.8 中与此等效的正确内容是什么? (2认同)