运行多个Tornado进程
我看过很多关于如何运行N个Tornado进程的文章和教程,其中N是核心数。我之前的代码可以在16个核心上正常运行,但我不小心搞错了,现在需要有人帮我看看。
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()
这段代码报了这个错:
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()
我就是看不出来问题出在哪里。谢谢你们。
:编辑:
正如Ben所说,我的一个方法出了问题。这是那个方法的代码,可能对其他人有帮助:
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()
编辑2
我找到了问题的最终解决方案。正如Ben指出的,上面的那个方法让我很头疼。正确的方式是按照Motor文档中说明的来使用Motor和Tornado应用。这里有一段对我有效的代码:
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()
3 个回答
0
我也遇到了同样的问题,尽管我把 debug=False
和 autoreload=False
设置了。
我怀疑问题出在 MotorClient
,因为它是在 TornadoApp.__init__()
中创建的。
把 motor_client = ...
这一行注释掉后,问题就解决了。
class MainApp(tornado.web.Application):
def __init__(self):
handlers = [
(r"/", views.HomeHandler),
(r".*", views.NotFoundHandler),
]
motor_client = motor.motor_tornado.MotorClient('mongodb://localhost:27017')
不幸的是,使用 MotorClient
让我不得不放弃在多进程下运行 Tornado。
15
这个异常是在使用tornado.web.Application的调试模式时出现的。
application = tornado.web.Application([
(r"/", hello),
],
debug=False)
把调试模式设置为关闭(False)可以解决这个问题。
你可以启动多个进程来监听不同的端口:
server = tornado.httpserver.HTTPServer(application)
server.bind(1234) # port
server.start(4)
tornado.ioloop.IOLoop.instance().start()
6
如果我把“core”和“services”的导入注释掉,程序就能正常工作。看起来这两个模块中的某个东西在初始化单例事件循环(可能是间接的,比如创建了一个全局的 AsyncHTTPClient 实例)。这个警告是为了提醒你,父进程中创建的这些对象在子进程中是无法使用的。你需要找到这些对象被创建的地方(可惜目前没有好的工具来帮助你找到这些),然后把它们移动到 fork 之后,这样它们就会在子进程中被创建。