17.odoo入门——初探后台启动过程(四)
来源:互联网 发布:linux搭建telnet服务 编辑:程序博客网 时间:2024/06/07 01:50
第17天——————————
因为odoo服务器有三种模式——prefork, gevented, threaded,首先得大致了解一下这三种MPM(Multi-Processing Module,多进程处理模块)模式的特点,可以参考一篇关于apache服务器的博文: http://blog.jobbole.com/91920/
读了这篇博文之后大致了解了这三种模式的区别和优缺点。
接下来看到我们的源代码,由于GeventServer,PreforkServer,ThreadedServer三个类都继承于CommonServer类,其源代码如下:
class CommonServer(object): def __init__(self, app): # TODO Change the xmlrpc_* options to http_* self.app = app #传入的参数是 odoo.service.wsgi_server.application ,先搁置着 # config self.interface = config['xmlrpc_interface'] or '0.0.0.0' #在我的配置文件中为空 self.port = config['xmlrpc_port’] #在配置文件中可以查看到,xmlrpc_port = 8069 # runtime self.pid = os.getpid() def close_socket(self, sock): #反正就是关闭套接字啰 """ Closes a socket instance cleanly :param sock: the network socket to close :type sock: socket.socket """ try: sock.shutdown(socket.SHUT_RDWR) except socket.error, e: if e.errno == errno.EBADF: # Werkzeug > 0.9.6 closes the socket itself (see commit # https://github.com/mitsuhiko/werkzeug/commit/4d8ca089) return # On OSX, socket shutdowns both sides if any side closes it # causing an error 57 'Socket is not connected' on shutdown # of the other side (or something), see # http://bugs.python.org/issue4397 # note: stdlib fixed test, not behavior if e.errno != errno.ENOTCONN or platform.system() not in ['Darwin', 'Windows']: raise sock.close()
由于我的配置中使用的是threaded,那么看到ThreadedServer类:
首先这个类里面有比较多的函数,这里不贴一整段代码,而是一个函数一个函数去查看源码,首先要了解signal handler的概念,其实,要看懂几个常用的结束信号,可以参考:
http://blog.csdn.net/yikai2009/article/details/8643818 linux下的几个信号。 而cron是linux下的一个定时执行工具,大概是可以定时分配cpu给每个线程吧——自行百度吧
linux下的spawn,参考——http://blog.csdn.net/ysdaniel/article/details/7059511
Import threading #这个模块中导入了这个库,python内置的多线程处理的库
类的构造函数:
def __init__(self, app): super(ThreadedServer, self).__init__(app) self.main_thread_id = threading.currentThread().ident # Variable keeping track of the number of calls to the signal handler defined # below. This variable is monitored by ``quit_on_signals()``. self.quit_signals_received = 0 #统计收到的退出信号 #self.socket = None self.httpd = None
信号处理函数:
def signal_handler(self, sig, frame): #应该就是收到2次结束信号就退出 if sig in [signal.SIGINT, signal.SIGTERM]: # shutdown on kill -INT or -TERM self.quit_signals_received += 1 if self.quit_signals_received > 1: # logging.shutdown was already called at this point. sys.stderr.write("Forced shutdown.\n") os._exit(0) elif sig == signal.SIGHUP: # restart on kill -HUP odoo.phoenix = True self.quit_signals_received += 1
再挑顺序看到ThreadedServer类的start函数:
def start(self, stop=False): _logger.debug("Setting signal handlers") #就是这里了,控制台每次启动都会出的一条语句来自这里 if os.name == 'posix': #对linux定义几个声明 signal.signal(signal.SIGINT, self.signal_handler) signal.signal(signal.SIGTERM, self.signal_handler) signal.signal(signal.SIGCHLD, self.signal_handler) signal.signal(signal.SIGHUP, self.signal_handler) signal.signal(signal.SIGQUIT, dumpstacks) signal.signal(signal.SIGUSR1, log_ormcache_stats) elif os.name == 'nt': import win32api win32api.SetConsoleCtrlHandler(lambda sig: self.signal_handler(sig, None), 1) test_mode = config['test_enable'] or config['test_file'] if test_mode or (config['xmlrpc'] and not stop): # some tests need the http deamon to be available... self.http_spawn() #执行了这条语句 if not stop: # only relevant if we are not in "--stop-after-init" mode self.cron_spawn()
由输出调试后可知,我们进入了self.http_spawn()这条语句,
看到ThreadedServer下的这个函数:
def http_spawn(self): t = threading.Thread(target=self.http_thread, name="odoo.service.httpd") #参考 http://python.jobbole.com/81546/#参数target是一个可调用对象(也称为活动[activity]),在线程启动后执行; t.setDaemon(True) t.start() _logger.info('HTTP service (werkzeug) running on %s:%s', self.interface, self.port)#每次启动都会看到的这句话,原来输出是来自于这里再看到http_thread这个东西,它来自于ThreadedServer类下的这个函数:
def http_thread(self): def app(e, s): return self.app(e, s) self.httpd = ThreadedWSGIServerReloadable(self.interface, self.port, app) self.httpd.serve_forever()
而ThreadedWSGIServerReloadable的大致源代码为:
class ThreadedWSGIServerReloadable(LoggingBaseWSGIServerMixIn, werkzeug.serving.ThreadedWSGIServer): """ werkzeug Threaded WSGI Server patched to allow reusing a listen socket given by the environement, this is used by autoreload to keep the listen socket open when a reload happens. """ def __init__(self, host, port, app): super(ThreadedWSGIServerReloadable, self).__init__(host, port, app, handler=RequestHandler)….若干函数
这个暂时不太了解werkzeug.serving.ThreadedWSGIServer,但是大致知道应该是个处理http的web服务器程序,那么到此我们就大概了解了ThreadedServer类的启动和运行过程了。这里接触到的一个知识点就是,ThreadedServer类通过接受信号来知道自己是否被kill——这也算是进程间的通讯吧。
看到启动过程中控制台的最后一句输出:
INFO ? odoo.service.server: HTTP service (werkzeug) running on 0.0.0.0:8069那么也就是说 http 服务器是跟ThreadedServer类下的http_thread,也就是 http_thread这个函数啦。
由自己输出调试可知,接下来执行了
def cron_spawn(self): """ Start the above runner function in a daemon thread. The thread is a typical daemon thread: it will never quit and must be terminated when the main process exits - with no consequence (the processing threads it spawns are not marked daemon). """ # Force call to strptime just before starting the cron thread # to prevent time.strptime AttributeError within the thread. # See: http://bugs.python.org/issue7980 datetime.datetime.strptime('2012-01-01', '%Y-%m-%d') for i in range(odoo.tools.config['max_cron_threads']): def target(): self.cron_thread(i) #print "one”#这是我自己的输出调试 t = threading.Thread(target=target, name="odoo.service.cron.cron%d" % i) t.setDaemon(True) t.start() _logger.debug("cron%d started!" % i)
这里是根据配置文件中的参数max_cron_threads开启了若干个线程,线程启动后运行的便是cron_thread函数,看到这个函数源码:
def cron_thread(self, number): while True: time.sleep(SLEEP_INTERVAL + number) # Steve Reich timing style registries = odoo.modules.registry.Registry.registries _logger.debug('cron%d polling for jobs', number) for db_name, registry in registries.iteritems(): while registry.ready: try: acquired = odoo.addons.base.ir.ir_cron.ir_cron._acquire_job(db_name) if not acquired: break except Exception: _logger.warning('cron%d encountered an Exception:', number, exc_info=True) break
大概就是先睡眠一定的时间,睡眠完成后变成就绪状态,就可以等待工作的到来而获得cpu.不过从我的输出调试来看,在我不进行任何操作的时候,多个线程轮流切换,但是也没有进行执行任何有意义的行动,因为acquired总是空,而且目前我也还没找到odoo.addons.base.ir.ir_cron.ir_cron._acquire_job,那么这个问题暂且搁置
下一步要探讨的地方应该是 werkzeug.serving.ThreadedWSGIServer 这样的一个http服务器 和 多线程具体执行的工作, 以及在我们打开8069这个网页的时候后台都做了些什么工作。
- 17.odoo入门——初探后台启动过程(四)
- 16.odoo入门——初探后台启动过程(三)
- 7.odoo入门——初探odoo后台启动过程(一)
- 8.odoo入门——初探odoo后台启动过程(二)
- 19.odoo入门——odoo的session
- 10.11.12.odoo入门——杂记
- 20.odoo入门——杂记
- 21.odoo入门——杂记
- 22.odoo入门——工作杂记
- 23.odoo入门——工作杂记
- 24.odoo入门——工作杂记
- Odoo 8.0深入浅出开发教程(四) Odoo入门
- 8.odoo入门——jinja2入门(一)
- 18.odoo入门——odoo权限控制(一)模型(数据表)级别权限控制
- Application启动过程初探
- 6.odoo入门——培训签到课程项目(三)
- 13.odoo入门——杂记之git
- 26.odoo入门——工作杂记之many2one
- 你所看到较轻松的Dagger2(基础介绍)
- 前沿技术:改良版的UDP协议QUIC将成为未来谷歌网站新标准
- [置顶] Android输入输出机制之来龙去脉之前生后世
- 标准库vector类型
- [置顶] 安卓高手之路之 WindowManager
- 17.odoo入门——初探后台启动过程(四)
- Ignatius and the Princess IV||HDU1029
- [置顶] 自己动手实现OpenGL之glViewPort(一)
- LINK : fatal error LNK1158: cannot run 'rc.exe'
- 时间戳转换成时间
- eclipse导入maven项目出现Missing artifact *.jar
- [置顶] 自己动手实现OpenGL-OpenGL原来如此简单(二)
- 项目管理——实践入门
- js02.date和Math函数