Я использую api-сервер Python с приложением Tornado.Мое приложение Tornado использует tornado.web
и определено как
from tornado import web
def application():
handlers = [
# apis
(r'/api/1', th.APIHandler1),
(r'/api/2', th.APIHandler2)
]
settings = dict()
return web.Application(handlers, **settings)
Так что оно работает в IOLoop как
app = application()
app.listen(int(PORT))
ioloop.IOLoop.instance().start()
Так что это не приложение WSGI.Обработчики, как правило, будут украшены шаблоном @tornado.web.asynchronous
, а для задач с интенсивным использованием процессора - шаблоном @tornado.gen.coroutine
или в некоторых конкретных случаях для задач с большой продолжительностью работы с декоратором @tornado.concurrent.run_on_executor
для запуска в качестве потока в пуле потоков.В этом конкретном случае я использую исполнитель ограниченного пула потоков , например:
class MyHandler2(tornado.web.RequestHandler):
executor = BoundedThreadPoolExecutor(max_workers=5)
@tornado.concurrent.run_on_executor
def get(self, *args):
Я хочу перенести это на gunicorn
, чтобы воспользоваться преимуществом подхода, предшествующего работе с форками.Возможное решение, которое я исследовал, - это шаблон многопользовательского приложения gunicorn , который должен выглядеть следующим образом:
from routes import Mapper
from test import app as apiHandler1
from test import app as apiHandler2
class Application(object):
def __init__(self):
self.map = Mapper()
self.map.connect('app1', '/api/1', app=apiHandler1)
self.map.connect('app2', '/api/2', app=apiHandler2)
def __call__(self, environ, start_response):
match = self.map.routematch(environ=environ)
if not match:
return self.error404(environ, start_response)
return match[0]['app'](environ, start_response)
app = Application()
Нет конкретных документов по переносу асинхронного приложения Tornado в приложение gunicorn wsgi, поэтому мойвопрос в том, может ли этот подход быть правильным.