Ответ 1
Проблема заключается в том, что вы не можете просто вызвать существующий синхронный код, как если бы он был asyncio.coroutine
и получить асинхронное поведение. Когда вы вызываете yield from searching(...)
, вы получите асинхронное поведение, если searching
сам по себе является asyncio.coroutine
или, по крайней мере, возвращает asyncio.Future
. Прямо сейчас searching
является просто регулярной синхронной функцией, поэтому вызов yield from searching(...)
просто собирается выдать ошибку, потому что она не возвращает Future
или сопрограмму.
Чтобы получить нужное поведение, вам нужно иметь асинхронную версию searching
в дополнение к версии synchronous
(или просто полностью отказаться от синхронной версии, если она вам не понадобится). У вас есть несколько вариантов поддержки обоих:
- Перепишите
searching
какasyncio.coroutine
, что он используетasyncio
-компонентные вызовы для выполнения ввода-вывода, а не для блокировки ввода-вывода. Это заставит его работать в контекстеasyncio
, но это означает, что вы больше не сможете вызывать его прямо в синхронном контексте. Вместо этого вам также необходимо предоставить альтернативный синхронный методsearching
, который запускает цикл событийasyncio
и вызываетreturn loop.run_until_complete(self.searching(...))
. Подробнее см. этот вопрос. -
Сохраняйте синхронную реализацию
searching
и предоставляйте альтернативный асинхронный API, который используетBaseEventLoop.run_in_executor
для запускаsearching
в фоновом потоке:class search(object): ... self.s = some_search_engine() ... def searching(self, *args, **kwargs): ret = {} ... return ret @asyncio.coroutine def searching_async(self, *args, **kwargs): loop = kwargs.get('loop', asyncio.get_event_loop()) try: del kwargs['loop'] # assuming searching doesn't take loop as an arg except KeyError: pass r = yield from loop.run_in_executor(None, self.searching, *args) # Passing None tells asyncio to use the default ThreadPoolExecutor return r
Тестирование script:
s = search() loop = asyncio.get_event_loop() loop.run_until_complete(s.searching_async(arg1, arg2, ...)) loop.close()
Таким образом, вы можете сохранить свой синхронный код как есть и по крайней мере предоставить методы, которые могут использоваться в
asyncio
, без блокировки цикла событий. Это не так чистое решение, как если бы вы использовали асинхронный ввод-вывод в вашем коде, но лучше, чем ничего. - Предоставьте две полностью отдельные версии
searching
, которые используют блокирующий ввод-вывод, и один, которыйasyncio
-совместим. Это дает идеальные реализации для обоих контекстов, но требует удвоенной работы.