首页 文章

异步def和调用堆栈

提问于
浏览
4

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

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()
  • 在上面的例子中,我是否需要将整个func1 / 2/3的调用堆栈作为异步并等待所有这些? (恐怕回答是肯定的)

  • 我可以互换地将FileDataSource和SocketDataSource传递给func1,还是需要根据异步和非异步调用更改整个调用层次结构?

  • 设计这样的可以作为服务器或批处理运行的东西的最佳方法是什么?

非常感谢所有的帮助!

1 回答

  • 3

    如果callstack中的一个函数是异步的,我是否需要使整个堆栈异步并等待每次调用?

    答案取决于调用堆栈中的函数究竟是什么,但很可能是肯定的 . await effects需要异步函数与其调用者(awaiter或事件循环驱动程序)进行通信,以确保暂停/恢复其执行 .

    非异步函数可以在不等待的情况下参与调用堆栈,但是它只能用于传输协程对象而无法检查数据 . 例如, func3 可以实现为:

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

    要么:

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

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

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

    一旦将调用堆栈中的所有函数设置为异步,就无法传递 FileDataSource ,但这并不意味着您必须具有两个单独的调用层次结构 . 通过将 def getData() 更改为 async def getData() (以及其他方式保持实现不变),只需将 FileDataSource 实现为"async",并且它将用于异步使用,前提是它实际上不会阻塞 .

相关问题