асинхронное определение и стек вызовов - PullRequest
0 голосов
/ 03 июля 2018

При использовании asyncio с Python 3.6, если одна функция глубоко в стеке вызовов является асинхронной, нужно ли делать весь стек асинхронным и ставить await при каждом вызове?
Например у меня есть:

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 голосов
/ 03 июля 2018

если одна функция глубоко в стеке вызовов является асинхронной, нужно ли делать весь стек асинхронным и ставить await при каждом вызове?

Ответ зависит от того, что именно выполняют функции в стеке вызовов, но, скорее всего, да. await аффекты требуют, чтобы асинхронная функция взаимодействовала со своим вызывающим абонентом - либо с ожидающим, либо с драйвером цикла событий - для обеспечения приостановки / возобновления ее выполнения.

Неасинхронная функция может участвовать в стеке вызовов без ожидания, но затем она может использоваться только для передачи объекта сопрограммы и не может проверять данные. Например, func3 может быть реализовано как:

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

или

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

Но первая функция может проверять (или регистрировать и т. Д.) Данные, возвращаемые getData, тогда как вторая функция немедленно завершает работу и возвращает объект сопрограммы, который должен ждать кто-то другой.

Могу ли я поочередно передать FileDataSource и SocketDataSource в func1 или мне нужно изменить всю иерархию вызовов на основе асинхронных и не асинхронных вызовов?

Как только вы сделаете все функции в стеке вызовов асинхронными, вы не сможете передать FileDataSource, но это не значит, что вам нужно иметь две отдельные иерархии вызовов. Просто реализуйте FileDataSource как тривиально «асинхронный», изменив def getData() на async def getData() (и в противном случае оставив реализацию без изменений), и она будет работать для асинхронного использования, при условии, что она фактически не блокируется.

...