zoukankan      html  css  js  c++  java
  • gunicorn syncworker 源码解析

      gunicorn支持不同的worker类型,同步或者异步,异步的话包括基于gevent、基于eventlet、基于Aiohttp(python版本需要大于3.3),也有多线程的版本。下面是gunicorn当前版本(19.6.0)支持的Worker类型:
    • sync
    • eventlet - Requires eventlet >= 0.9.7
    • gevent - Requires gevent >= 0.13
    • tornado - Requires tornado >= 0.2
    • gthread - Python 2 requires the futures package to be installed
    • gaiohttp - Requires Python 3.4 and aiohttp >= 0.21.5
    本文主要对同步模型进行分析。同步模型实现(gunicorn.workers.sync.SyncWorker)继承自gunicorn.workers.base.Worker,绝大多数方法都是定义在基类,包括
    init_signal
        注册信号处理函数
    handle_xxx:
        各个信号具体的处理函数
    notify:
        通知父进程自己还活着
    run:
        需要子类实现的接口,用于处理具体的请求。
    init_process:
        提供给Arbiter的接口,调用inti_signal和run方法
    SyncWorker实现了run方法,对HTTP请求进程处理
    def run(self):    
           if len(self.sockets) > 1:
                self.run_for_multiple(timeout) # 使用select
           else:
                self.run_for_one(timeout)        # 如果只有一个监听socket,那么阻塞accept就行了
      run方法根据监听的端口数量进行区分,如果只在一个端口监听,那么调用accept; 如果是多个端口,那么用select轮训再accept。不管哪种方式,新的连接请求到达后 都调用handle_request函数处理,源代码如下:
      
    复制代码
        def handle_request(self, listener, req, client, addr):
            environ = {}
            resp = None
            try:
                self.cfg.pre_request(self, req)
                request_start = datetime.now()
                resp, environ = wsgi.create(req, client, addr,
                        listener.getsockname(), self.cfg)
                # Force the connection closed until someone shows
                # a buffering proxy that supports Keep-Alive to
                # the backend.
                resp.force_close()
                self.nr += 1
                if self.nr >= self.max_requests:
                    self.log.info("Autorestarting worker after current request.")
                    self.alive = False
                respiter = self.wsgi(environ, resp.start_response)
                try:
                    if isinstance(respiter, environ['wsgi.file_wrapper']):
                        resp.write_file(respiter)
                    else:
                        for item in respiter:
                            resp.write(item)
                    resp.close()
                    request_time = datetime.now() - request_start
                    self.log.access(resp, req, environ, request_time)
    复制代码

      其中,调用到App的是下面这行代码

       respiter = self.wsgi(environ, resp.start_response)
      前面提到worker通过notify来向master进程做心跳,具体的代码在WorkerTmp.py。原理很简单:
        (1)首先通过tempfile.mkstemp创建一个临时文件
        (2)worker进程在每次轮训的时候修改该临时文件的属性
        
    复制代码
        def notify(self):
            try:
                self.spinner = (self.spinner + 1) % 2
                os.fchmod(self._tmp.fileno(), self.spinner)
            except AttributeError:
                # python < 2.6
                self._tmp.truncate(0)
                os.write(self._tmp.fileno(), b"X")
    复制代码
        (3)master进程检查临时文件最新一次修改时间是否超过阈值
        
        def last_update(self):
            return os.fstat(self._tmp.fileno()).st_ctime
    references:
  • 相关阅读:
    C# 创建Excel并写入内容
    c#中使用excel
    C#中EXCEL表格的内容进度条实现
    WinForm c#操作Excel
    如何使用 Visual C# .NET 处理 Excel 事件
    C#与Excel的交互示例
    c#操作excel方式三:使用Microsoft.Office.Interop.Excel.dll读取Excel文件
    C#在excel中添加超链接
    ASP.NET学习笔记(3)
    ASP.NET学习笔记(4)
  • 原文地址:https://www.cnblogs.com/yezuhui/p/6855657.html
Copyright © 2011-2022 走看看