ejecutar múltiples procesos de tornado

He leído varios artículos y tutoriales sobre cómo ejecutar el número N de procesos de Tornado, donde N = número de núcleos. Mi código estaba funcionando, corriendo en todos los 16 núcleos pero de alguna manera logré arruinarlo y necesito nuevos ojos en esto.

import tornado.ioloop import tornado.web import tornado.httpserver from core import settings from core import coreService import services from tornado.options import define, options, parse_command_line define("port", default=settings.SERVER_PORT, help="run on the given port", type=int) app = tornado.web.Application([ (r'/upload', coreService.Upload) ]) if __name__ == "__main__": tornado.options.parse_command_line() server = tornado.httpserver.HTTPServer(app, max_buffer_size=1024*1024*201) server.bind(options.port) # autodetect cpu cores and fork one process per core server.start(0) try: print 'running on port %s' % options.port tornado.ioloop.IOLoop.instance().start() except KeyboardInterrupt: tornado.ioloop.IOLoop.instance().stop() 

Este código arroja este error:

 File "/opt/tornado/tornado/process.py", line 112, in fork_processes raise RuntimeError("Cannot run in multiple processes: IOLoop instance " RuntimeError: Cannot run in multiple processes: IOLoop instance has already been initialized. You cannot call IOLoop.instance() before calling start_processes() 

Simplemente no lo veo. Gracias

:EDITAR:

Como dijo Ben, uno de mis métodos me estaba dando problemas. Este es el código de ese método, alguien puede beneficiarse de esto:

 from tornado import gen import motor db = motor.MotorClient().open_sync().proba class Upload(BaseHandler): @gen.engine def post(self): fs = yield motor.Op(motor.MotorGridFS(db).open) gridin = yield motor.Op(fs.new_file) yield motor.Op(gridin.write, 'First part\n') yield motor.Op(gridin.write, 'Second part') yield motor.Op(gridin.close) print gridin._id self.write(str(gridin._id)) self.finish() 

Editar 2

He encontrado la solución definitiva a mi problema. Como lo señaló Ben, el método anterior me estaba dando problemas. La forma correcta de incluir la aplicación Motor con Tornado está documentada en la documentación de Motor. Aquí hay una excepción que está trabajando para mí:

 if __name__ == "__main__": tornado.options.parse_command_line() try: server = tornado.httpserver.HTTPServer(app, max_buffer_size=1024*1024*201) server.bind(8888) server.start(0) # autodetect cpu cores and fork one process per core db = motor.MotorClient().open_sync().proba print 'running on port %s' % options.port # Delayed initialization of settings app.settings['db'] = db # from this point on db is available as self.settings['db'] tornado.ioloop.IOLoop.instance().start() except KeyboardInterrupt: tornado.ioloop.IOLoop.instance().stop() 

Funciona como se espera si comento las importaciones “principales” y “servicios”. Algo en uno de esos módulos debe estar inicializando el bucle de eventos de singleton (quizás de manera indirecta, por ejemplo, creando una instancia global de AsyncHTTPClient). Esta advertencia lo protege del hecho de que estos objetos que se crearon en el proceso principal no funcionarán en el secundario. Tendrá que encontrar los lugares donde se están creando estos objetos (desafortunadamente, no hay buenas herramientas para esto) y moverlos después de la bifurcación para que se creen en los procesos secundarios.

Esta excepción aumenta con el modo de depuración de tornado.web.Application.

 application = tornado.web.Application([ (r"/", hello), ], debug=False) 

Establezca debug en False para solucionar este problema.

Puedes iniciar varios procesos para escuchar cada puerto:

 server = tornado.httpserver.HTTPServer(application) server.bind(1234) # port server.start(4) tornado.ioloop.IOLoop.instance().start() 

Estaba sufriendo el mismo problema, incluso configuré debug=False y autoreload=False

Mi sospechoso se centró en MotorClient que al crear una instancia en TornadoApp.__init__()

Comentando motor_client = ... línea resolvió mi problema.

 class MainApp(tornado.web.Application): def __init__(self): handlers = [ (r"/", views.HomeHandler), (r".*", views.NotFoundHandler), ] motor_client = motor.motor_tornado.MotorClient('mongodb://localhost:27017') 

Desafortunadamente, el uso de MotorClient me obligó a renunciar a ejecutar Tornado con múltiples procesos.