2016-09-08 2 views
0

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

  • python2.7 родной
  • python2.7 Торнадо
  • Python3.5 asyncio

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

#Python2.7native.py 
def main(client): 
    client.foo(args) 
    client.bar(args) 

#Python2.7tornado.py 
@gen.coroutine 
def main(client): 
    yield client.foo(args) 
    yield client.bar(args) 

#Python3.5asyncio.py 
async def main(client): 
    await client.foo(args) 
    await client.bar(args) 

где client является языком конкретной реализации в, поддерживая родную питона, asyncio и торнадо соответственно. Вызов метода API идентичен.

Я надеюсь, чтобы иметь возможность как-то обобщить это в один метод, который я могу включить в общий файл, который соответствующим образом вызывает различные методы

Я думал об определении методов в отдельном файле и с помощью getattr, чтобы вызвать тест правильно, но это кажется действительно грязным.

Есть ли хороший способ сделать это?

+0

Если на самом деле они идентичны в разных разделах, за исключением того, d, можете ли вы создать список функций, а затем перечислить конкретный бегун для платформы через этот список и вызвать его соответствующим образом? –

+0

Проблема будет '' async def''. Насколько мне известно, нет 2,7 эквивалента. Если вам нужно разделить между несколькими версиями Python, то я бы выбрал '' gen.coroutine'' для этих функций. –

ответ

-1

Использование @gen.coroutine и yield: Это будет работать во всех версиях Python. Функция, украшенная gen.coroutine, немного медленнее, чем нативная сопрограмма, но может использоваться во всех тех же сценариях.

Для синхронного случае используйте run_sync:

result = IOLoop.current().run_sync(main) 
+0

Как это отвечает на мой вопрос? Мне нужно поддерживать asyncio, торнадо и обычные реализации python. – enderland

1

Вы не можете сделать все это в одной функции - как client.foo() должен знать, является ли это вызывается из «нормального» синхронного применения, или будет ли его вызывающий абонент использовать yield или await. Однако, если вы хотите иметь Tornado в качестве зависимости, вы можете избежать дублирования всего своего кода три раза.

В одном модуле, client_async.py, реализовать функцию (ы) с помощью смерча @gen.coroutine:

@gen.coroutine 
def foo(args): 
    yield something() 
    yield something_else() 
    raise gen.Return(another_thing()) 

В другом client_sync.py, завернуть каждую из функций из client_async.py в IOLoop.run_sync() для локального потока IOLoop, как это:

import client_async 
import threading 
import tornado.ioloop 

class _LocalIOLoop(threading.local): 
    def __init__(self): 
     self.value = tornado.ioloop.IOLoop() 
local_ioloop = _LocalIOLoop() 

def foo(args): 
    return local_ioloop.value.run_sync(lambda: foo_async.my_func(args)) 

Теперь вы можете использовать этот код из всех трех сред.Из нормального синхронного кода:

import client_sync 

def main(): 
    x = client_sync.foo(args) 

От Торнадо @gen.coroutine:

import client_async 

@gen.coroutine 
def main(): 
    x = yield client_async.foo(args) 

От async def и asyncio (обратите внимание, что два не являются синонимами - можно использовать async def с Торнадо без asyncio):

# one-time initialization for Tornado/asyncio integration 
import tornado.platform.asyncio 
tornado.platform.asyncio.AsyncIOMainLoop().install() 

import client_async 

async def main(): 
    x = await client_async.foo(args) 
Смежные вопросы