2013-12-22 4 views
3

Я кодирую фреймворк, где фреймворк будет вызывать функцию, предоставленную пользователем.maybeDeferred analog with asyncio

Я хочу, чтобы используемая функция, применяемый быть любой из следующих:

  • равнины функции
  • функция, возвращающая asyncio.Future
  • asyncio.coroutine

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

Витая hasdefer.maybeDeferred для этого. Что было бы asyncio способом?

У меня есть что-то вроде следующего (полного кода here):

import types 
types.GeneratorType 

def maybe_async(value): 
    if isinstance(value, types.GeneratorType) or \ 
     isinstance(value, asyncio.futures.Future): 
     return value 
    else: 
     future = asyncio.Future() 
     future.set_result(value) 
     return future 

, а затем вызвать функцию f поставляется пользователем, как это в рамках:

res = yield from maybe_async(f(x)) 

Это оборачивает любую равнину возвращаемое значение функции в Future - всегда. И я опасаюсь производительности или других последствий этого.

Является ли «рекомендуемым» способом?

У "inline" version of above code нет накладных расходов. Как я мог достичь наилучшего из обоих: никаких накладных расходов для «простого» случая, но дублирование кода для проверки async не возвращается по всей структуре?

+0

'maybeDeferred' принимает функцию вместо результата функции по причине. Что вы хотите, если 'f' вызывает синхронное исключение? –

+0

@ Jean-PaulCalderone поймать его (то же самое для всех вариантов): https://github.com/oberstet/scratchbox/blob/master/python/asyncio/test3.py#L96 – oberstet

+1

'res = выход из asyncio.coroutine (f) (x) ' – jfs

ответ

2

Подводя итог, кажется, есть две (основные) варианты:

Idiom 1:

res = f(x) 
if yields(res): 
    res = yield from res 

где

def yields(value): 
    return isinstance(value, asyncio.futures.Future) or inspect.isgenerator(value) 

или

Idiom 2 :

res = yield from asyncio.coroutine(f)(x) 
+0

Несвязанный: вы можете использовать имя 'asyncio.Future' вместо' asyncio.futures.Future'. – jfs