tornado 的 define 和options方法解读
一、源码解读
tornado是facebook开源的非阻塞web容器,类似java的netty,tornado.options是负责解析tornado容器的全局参数的,同时也能够解析命令行传递的参数和从配置文件中解析参数。使用步骤如下:
1. 源码中的示例代码,定义全局变量:
from tornado.options import define, options define("mysql_host", default="127.0.0.1:3306", help="Main user DB") define("memcache_hosts", default="127.0.0.1:11011", multiple=True, help="Main user memcache servers") def connect(): db = database.Connection(options.mysql_host) ...
2. 在模块的main函数中解析命令行参数或者配置文件
Your ``main()`` method can parse the command line or parse a config file with either:: tornado.options.parse_command_line() # or tornado.options.parse_config_file("/etc/server.conf")
命令行参数格式:--myoption=myvalue
配置文件可以是python文件,参数格式为:
myoption = "myvalue" myotheroption = "myothervalue"
3. Tornado.options默认是定义为单例模式的,通过tornado.options.options对象来维护全局参数,如果在线程中需要维护自己的变量,也可以使用tornado.options. OptionParser对象来维护参数。tornado.options.options就是通过实例OptionParser的对象来实现的,而且把define、parse_command_line、parse_config_file放到tornado.options 包中,可以直接使用,与调用tornado.options.options的方法是一致的。代码如下:
options = OptionParser() """Global options object. All defined options are available as attributes on this object. """ def define(name, default=None, type=None, help=None, metavar=None, multiple=False, group=None, callback=None): """Defines an option in the global namespace. See `OptionParser.define`. """ return options.define(name, default=default, type=type, help=help, metavar=metavar, multiple=multiple, group=group, callback=callback) def parse_command_line(args=None, final=True): """Parses global options from the command line. See `OptionParser.parse_command_line`. """ return options.parse_command_line(args, final=final) def parse_config_file(path, final=True): """Parses global options from a config file. See `OptionParser.parse_config_file`. """ return options.parse_config_file(path, final=final)
二、应用
# 在tornado.options.options配置变量名 from tornado.options import define, options define('debug', default=True, help='enable debug mode') define('project_path', default=sys.path[0], help='deploy_path') define('port', default=8888, help='run on this port', type=int) # 从命令行中解析参数信息, 如 python web.py --port=9002, 这里的port解析 tornado.options.parse_command_line()
使用参数
使用options获取刚设置的参数 from tornado.options import options .... application.listen(options.port) ..... settings = { 'debug': options.debug, }
完整代码
#!/usr/bin/env python # -*- coding: utf-8 -*- # vim: set et sw=4 ts=4 sts=4 ff=unix fenc=utf8: __author__ = 'okker.ma@gmail.com' import tornado.ioloop import tornado.web import os from tornado.options import options, define #在options中设置几个变量 define('debug', default=True, help='enable debug mode') define('port', default=9002, help='run on this port', type=int) # 解析命令行, 有了这行,还可以看到日志... tornado.options.parse_command_line() class MainHandler(tornado.web.RequestHandler): def get(self): self.write("hello,a world") settings = { 'debug': options.debug, 'gzip': True, 'autoescape': None, 'xsrf_cookies': False, 'cookie_secret': 'xxxxxxx' } application = tornado.web.Application([ (r'/', MainHandler) ], **settings) if __name__ == '__main__': application.listen(options.port) tornado.ioloop.IOLoop.instance().start()
运行:
python web.py --port=9002 --debug=True
示例二
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.httpserver import tornado.ioloop import tornado.web from tornado.options import define, options from test import aa define('config', default=None, help='tornado settings file', type=str) options.parse_command_line() if options.config: # print(options.settings) aa() else: raise Exception("You must add a xxx.py at settings/ folder, then run: 'python app.py --settings=user'") class IndexHandler(tornado.web.RequestHandler): def get(self): greeting = self.get_argument('greeting', 'Hello') self.write(greeting + ', friendly user!') if __name__ == "__main__": app = tornado.web.Application( handlers=[(r"/", IndexHandler)] ) http_server = tornado.httpserver.HTTPServer(app) http_server.listen(8000) tornado.ioloop.IOLoop.current().start()main.py
from tornado.options import options import importlib # db_config = importlib.import_module('settings.%s.db_config'%options.settings) # # options.config = { # 'MONGO': db_config.MONGO, # 'SETTINGS': {}, # } def aa(): data = dict(options.items()) print("asdfasdf", data["config"])other.py
注意 tornado如果启动多进程, option方法是不可实现的, 报错
tornado.options.Error: Option 'lalala' already defined in app.py
没找到解决办法
本文参考链接:(其实这篇是抄的, 哈哈哈)
1. https://blog.csdn.net/wgw335363240/article/details/50755782
2. https://my.oschina.net/jiemachina/blog/204875
三、多进程解决办法 ---》哈哈哈,找到解决办法啦~
怎么解决呢?,单利模式嘛,哈哈哈
一定要把options的东西放启动脚本的最上面, 要不下面调用的时候报错
问题出在哪呢?
多进程是启动多个,当已经define定义key的时候, OK, 可是同时启动多个啊, memory中已经有定义好的define的你定义的key了呀
判断一下嘛, 就好啦
#!/usr/bin/env python # -*- coding:utf-8 -*- from tornado.options import define, options try: if options.lalala: pass except: define('conf', default='zk_css.cnf', help='tornado settings file', type=str) import tornado import tornado.ioloop import tornado.web import os, sys from tornado.httpserver import HTTPServer from tornado.options import define, options from controllers.home_handlers import My404, write_error from common.util.include_url_model import url_wrapper, include from common.base import Config ServerPort = Config().get_content("server") define("port", default=ServerPort["serverport"], type=int) options.parse_command_line() _ROOT_PATH = os.path.dirname(__file__) ROOT_JOIN = lambda sub_dir: os.path.join(_ROOT_PATH, sub_dir) router = url_wrapper([ (r'', include('urls')), ]) settings = dict( template_path=ROOT_JOIN('views'), static_path=ROOT_JOIN('static'), # cookie_secret=Env.COOKIE_SEC, default_handler_class=None, debug=False ) tornado.web.RequestHandler.write_error = write_error application = tornado.web.Application(router, **settings) if __name__ == "__main__": server = HTTPServer(application, max_buffer_size=504857600) server.bind(options.port, address="0.0.0.0") server.start(10) # Forks multiple sub-process tornado.ioloop.IOLoop.current().start()app.py
#!/usr/bin/env python # -*- coding:utf-8 -*- import configparser import os, json, base64 from decimal import Decimal import datetime, time import pymongo # import MySQLdb import pymysql from common.log.loger import Logger import datetime, time, uuid, re import hashlib from common.error import * from other_url import BaseConf from tornado.options import define, options def my_options(arg): return dict(options.items())[arg] class Config(object): """ # Config().get_content("user_information") """ def __init__(self): # file_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "conf", BaseConf.BaseCnf) file_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "conf", my_options("conf")) self.cf = configparser.ConfigParser() self.cf.read(file_path) def get_sections(self): return self.cf.sections() def get_options(self, section): return self.cf.options(section) def get_content(self, section): result = {} for option in self.get_options(section): value = self.cf.get(section, option) result[option] = int(value) if value.isdigit() else value return resultBase.py
分割线
==========================================
屁, 他娘的,根本没解决,大爷的, 问题出在哪儿了,百度FORK() 函数,跟他有关
解决办法
#!/usr/bin/env python # -*- coding:utf-8 -*- from tornado.options import define, options if "conf" in dict(options.items()): pass else: define("conf", default='zk_css.cnf', help='tornado settings file', type=str) import tornado.web import os from tornado.httpserver import HTTPServer from tornado.options import define, options from controllers.home_handlers import My404, write_error from common.util.include_url_model import url_wrapper, include from common.base import Config ServerPort = Config().get_content("server") define("port", default=ServerPort["serverport"], type=int) options.parse_command_line() _ROOT_PATH = os.path.dirname(__file__) ROOT_JOIN = lambda sub_dir: os.path.join(_ROOT_PATH, sub_dir) router = url_wrapper([ (r'', include('urls')), ]) settings = dict( template_path=ROOT_JOIN('views'), static_path=ROOT_JOIN('static'), # cookie_secret=Env.COOKIE_SEC, default_handler_class=None, debug=False ) tornado.web.RequestHandler.write_error = write_error application = tornado.web.Application(router, **settings) if __name__ == "__main__": from tornado.netutil import bind_sockets from tornado.process import fork_processes from tornado.ioloop import IOLoop sockets = bind_sockets(port=options.port, address="0.0.0.0") fork_processes(10) server = HTTPServer(application, max_buffer_size=504857600) server.add_sockets(sockets) IOLoop.current().start()
分割线
===========================================
草,又特么不行了,为什么呢? 因为出现了两种不同结果, 麻痹的, 没找到解决办法
root@corleone:/opt/code/my_code/zk_css# python3 app.py --port=8010 --conf=zk_css_2.cnf base: zk_css.cnf base: zk_css.cnf base: zk_css.cnf ----》 看这儿 base: zk_css.cnf base: zk_css_2.cnf --》 看这儿 base: zk_css_2.cnf base: zk_css_2.cnf /usr/local/lib/python3.5/dist-packages/statsmodels/compat/pandas.py:56: FutureWarning: The pandas.core.datetools module is deprecated and will be removed in a future version. Please use the pandas.tseries module instead. from pandas.core import datetools base: zk_css_2.cnf base: zk_css_2.cnf base: zk_css_2.cnf base: zk_css_2.cnf base: zk_css_2.cnf base: zk_css_2.cnf base: zk_css_2.cnf base: zk_css_2.cnf zk_css_2.cnf 8010 [I 180906 16:56:49 process:133] Starting 10 processes