我用Tornado写了一个简单的http服务器,但有时会引发下面的异常,self.session.response
在一个线程池中运行。
服务器代码:
class AuToServer(object):
module_path = os.path.split(os.path.realpath(__file__))[0] + '/../module/'
def __init__(self, prefix=DEFAULT_PREFIX, work_root=module_path, module=[], **kwargs):
self._prefix = prefix
self._thread_pool = ExecutorDelegate(20)
self._module_manager = ModuleManager(work_root)
self.initilize(module, kwargs)
def initilize(self, modules, kwargs):
self._module_manager.set_args(kwargs)
if not self._module_manager.prepare(modules):
print "initilize module fail. [%s]" % (str(modules))
raise AppInitError("initilize %s fail" % (modules))
def __call__(self, request): # request handler
session = Session(request)
if not session.parse(self._prefix):
print "parse query fail. [%s]" % (session.query)
session.response("url parse fail [%s]\n" % session.query)
return
self._thread_pool.submit(WorkerHander(self._module_manager, session))
def start(self, port=8880):
http_server = tornado.httpserver.HTTPServer(self, max_header_size=128*1024)
http_server.listen(port)
tornado.ioloop.IOLoop.instance().start()
代码WorkerHander
:
class WorkerHander(BaseExecutor):
def __init__(self, module_manage, session):
self.module_manage = module_manage
self.session = session
super(WorkerHander, self).__init__(self)
def run(self):
method = self.session.get_command()
if not method:
self.session.response("invalid url [%s]\n" % (self.session.query))
return
context = self.module_manage.run(method, self.session)
try:
if context:
self.session.response(context) # raise exception
else:
self.session.response("None\n")
except Exception, error:
Logger.warning("session response fail. [%s][%s]" % (self.session.query, traceback.format_exc()))
代码session.response
def response(self, context):
if not self.request:
return False
if isinstance(context, unicode):
context = context.encode("utf8")
self.request.write(utf8("%s %d\r\n\r\n%s" % (
HTTP_HEADER,
len(context),
context)))
Logger.debug("QUERY:[cmd:%s][%s] [%s] [%s]" % (
self.command,
time.time() - self.begin_time,
self.request.remote_ip,
self.query))
self.request.finish()
return True
异常:
2016-02-29 16:29:26,852 WARNING: server.py:run:94: session response fail. [/auto?start_timestamp=1456730772&_cmd=get_index_info][Traceback (most recent call last):
File "/home/admin/autobots/lib/python2.7/site-packages/autobase-0.0.1-py2.7.egg/autobase/service/server.py", line 90, in run
self.session.response(context)
File "/home/admin/autobots/lib/python2.7/site-packages/autobase-0.0.1-py2.7.egg/autobase/service/session.py", line 43, in response
self.request.finish()
File "/home/admin/autobots/lib/python2.7/site-packages/tornado-4.2-py2.7-linux-x86_64.egg/tornado/httputil.py", line 407, in finish
self.connection.finish()
File "/home/admin/autobots/lib/python2.7/site-packages/tornado-4.2-py2.7-linux-x86_64.egg/tornado/http1connection.py", line 459, in finish
self._pending_write.add_done_callback(self._finish_request)
File "/home/admin/autobots/lib/python2.7/site-packages/tornado-4.2-py2.7-linux-x86_64.egg/tornado/concurrent.py", line 243, in add_done_callback
fn(self)
File "/home/admin/autobots/lib/python2.7/site-packages/tornado-4.2-py2.7-linux-x86_64.egg/tornado/http1connection.py", line 491, in _finish_request
self.close()
File "/home/admin/autobots/lib/python2.7/site-packages/tornado-4.2-py2.7-linux-x86_64.egg/tornado/http1connection.py", line 297, in close
self.stream.close()
File "/home/admin/autobots/lib/python2.7/site-packages/tornado-4.2-py2.7-linux-x86_64.egg/tornado/iostream.py", line 427, in close
self.close_fd()
File "/home/admin/autobots/lib/python2.7/site-packages/tornado-4.2-py2.7-linux-x86_64.egg/tornado/iostream.py", line 995, in close_fd
self.socket.close()
AttributeError: 'NoneType' object has no attribute 'close'
]
我是否以错误的方式使用龙卷风?请求帮忙。感谢〜
答案 0 :(得分:2)
龙卷风的设计是not thread-safe。您可以使用线程池来完成自己的工作,但必须从self.request.write
线程调用所有Tornado方法(在本例中包括self.request.finish
和IOLoop
)。