异步定义和调用堆栈

时间:2018-07-02 22:18:30

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

在Python 3.6上使用asyncio时,如果调用栈中的一个函数是异步的,我是否需要使整个堆栈异步并在每次调用时都处于等待状态?
例如,我有:

class FileDataSource:  
    def getData(self):  
        return pd.read_csv('/some/file')

class SocketDataSource:
    def __init__(self, host, port):
        self.reader, self.writer = yield from asyncio.open_connection(host, port)

    async def getData(self):
        data = await self.reader.readuntil(b'\n\n')
        return data

def func1(datasource):
    func2(datasource)

def func2(datasource):
    func3(datasource)

def func3(datasource):
    datasource.getData()

def main(host, port):
    if host is None:
        func1(FileDataSource())
    else:
        loop = asyncio.get_event_loop()
        for timeout in range(1, 60):
            loop.call_later(timeout, func1(SocketDataSource(host, port)))
        loop.run_forever()
  1. 在上面的示例中,我是否需要将func1 / 2/3的整个调用堆栈设为异步并等待所有这些调用? (恐怕答案是肯定的)

  2. 我可以互换地将FileDataSource和SocketDataSource传递给func1还是我需要基于异步与非异步调用更改整个调用层次结构?

  3. 设计可以作为服务器或批处理运行的类似内容的最佳方法是什么?

非常感谢所有帮助!

1 个答案:

答案 0 :(得分:3)

  

如果调用堆栈中的一个函数是异步的,我是否需要使整个堆栈异步并在每次调用时都处于等待状态?

答案取决于调用堆栈中函数的确切功能,但很可能是。 await的影响要求异步功能与其调用方(即等待方或事件循环驱动程序)进行通信,以确保中止/恢复执行。

非异步功能可以不等待而参与调用堆栈,但是它只能用于传输协程对象,并且不能检查数据。例如,func3可以实现为:

async def func3(datasource):
    return await datasource.getData()

或:

def func3(datasource):
    return datasource.getData()

但是第一个函数可以检查(或记录等)getData返回的数据,而第二个函数立即退出并返回其他人必须等待的协程对象。

  

我可以互换地将FileDataSourceSocketDataSource传递给func1还是需要基于异步与非异步呼叫来更改整个呼叫层次结构?

一旦使调用栈中的所有功能异步,您将无法传递FileDataSource,但这并不意味着您必须具有两个单独的调用层次结构。只需将FileDataSource更改为def getData()即可将async def getData()实现为“异步”(否则将实现保持不变),并且只要不实际阻塞,它将适用于异步使用。