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 result
Base.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