cherrypy & gevent patch

给cherrypy 打gevent WSGIServer的patch

1. patch Serving 类

2. 关闭python的原生WSGIServer

具体使用例子参考 我的开源项目  https://github.com/thomashuang/Lilac

#!/usr/bin/env python

import cherrypy
from cherrypy import _cprequest
from cherrypy.lib import httputil
import sys
import logging
from cherrypy.process import servers

LOGGER = logging.getLogger(‘web.patch‘)

try:
    from greenlet import getcurrent as get_ident
except ImportError:
    LOGGER.ERROR(‘You shall install Gevent, if wanna use gevent wsgi server‘)
    exit(1)

def patch_cherrypy():
    cherrypy.serving = GreenletServing()

class GreenletServing(object):
    __slots__ = (‘__local__‘, )

    def __init__(self):
        object.__setattr__(self, ‘__local__‘, {})
        ident = get_ident()
        self.__local__[ident] = {
            ‘request‘: _cprequest.Request(httputil.Host("127.0.0.1", 80), httputil.Host("127.0.0.1", 1111)),
            ‘response‘: _cprequest.Response()
        }

    def load(self, request, response):
        self.__local__[get_ident()] = {
            ‘request‘: request,
            ‘response‘: response
        }

    def __getattr__(self, name):
        try:
            return self.__local__[get_ident()][name]
        except KeyError:
            raise AttributeError(name)

    def __setattr__(self, name, value):
        ident = get_ident()
        local = self.__local__
        try:
            local[ident][name] = value
        except KeyError:
            local[ident] = {name: value}

    def clear(self):
        """Clear all attributes of the current greenlet."""
        del self.__local__[get_ident()]
#!/usr/bin/env python

import cherrypy
import sys
import logging
from cherrypy.process import servers

LOGGER = logging.getLogger(‘web.server‘)

class GeventWSGIServer(object):

    """Adapter for a gevent.wsgi.WSGIServer."""

    def __init__(self, *args, **kwargs):
        from lilac.web.patch import patch_cherrypy

        patch_cherrypy()
        self.args = args
        self.kwargs = kwargs
        self.ready = False

    def start(self):
        """Start the GeventWSGIServer."""
        # We have to instantiate the server class here because its __init__
        from gevent.wsgi import WSGIServer

        self.ready = True
        LOGGER.debug(‘Starting Gevent WSGI Server...‘)
        self.httpd = WSGIServer(*self.args, **self.kwargs)
        self.httpd.serve_forever()

    def stop(self):
        """Stop the HTTP server."""
        LOGGER.debug(‘Stoping Gevent WSGI Server...‘)
        self.ready = False
        self.httpd.stop()

class WebServer(object):

    def __init__(self, server_name=‘Sola‘, host=‘127.0.0.1‘, port=8080, use_gevent=True, debug=False, encoding=‘UTF-8‘):
        self.server_name = server_name
        self.host = host
        self.port = port
        self.debug = debug
        self.encoding = encoding
        self.use_gevent = use_gevent
        self.config = self.gen_config()
        self.bootstrap()

    def bootstrap(self):
        """You can intialize more configs or settings in here"""
        pass

    def gen_config(self):
        conf = {
            ‘global‘:
                {
                    ‘server.socket_host‘: self.host,
                    ‘server.socket_port‘: self.port,
                    ‘engine.autoreload.on‘: self.debug,
                    #‘log.screen‘: self.debug,
                    ‘log.error_file‘: ‘‘,
                    ‘log.access_file‘: ‘‘,
                    ‘request.error_response‘: self.handle_internal_exception,
                    ‘tools.decode.on‘: True,
                    "tools.encode.on": True,
                    ‘tools.encode.encoding‘: self.encoding,
                    ‘tools.gzip.on‘: True,
                    ‘tools.log_headers.on‘: False,
                    ‘request.show_tracebacks‘: False,
                }
        }
        if self.use_gevent:
            conf[‘global‘][‘environment‘] = ‘embedded‘

        return conf

    def set_404_pape(self, not_found_handler):
        """Custom not found page"""
        self.config[‘global‘][‘error_page.404‘] = not_found_handler

    def asset(self, path, asset_path):
        """Set servering Static directory"""
        self.config[path] = {
            ‘tools.staticdir.on‘: True,
            ‘tools.staticdir.dir‘: asset_path
        }

    def handle_internal_exception(self):
        """Handle the unknow exception and also throw 5xx status and push message to frontend"""
        cls, e, tb = sys.exc_info()

        LOGGER.exception(‘Unhandled Error %s‘, e)
        resp = cherrypy.response
        resp.status = 500
        resp.content_type = ‘text/html; charset=UTF-8‘

        if cherrypy.request.method != ‘HEAD‘:
            resp.body = ["""<html>
<head><title>Internal Server Error </title></head>
<body><p>An error occurred: <b>%s</b></p></body>
</html> """ % (str(e))]

    def new_route(self):
        return cherrypy.dispatch.RoutesDispatcher()

    def create_app(self):
        raise NotImplemented(‘Must implement create_app in Subclass‘)

    def _bootstrap_app(self):
        ctl, routes = self.create_app()
        cherrypy.config.clear()
        config = {‘/‘: {‘request.dispatch‘: routes}, ‘global‘: self.config}
        config.update(self.config)
        cherrypy.config.update(config)
        return cherrypy.tree.mount(ctl, ‘/‘, config)

    def serve_forever(self):
        engine = cherrypy.engine
        if hasattr(engine, "signal_handler"):
            engine.signal_handler.subscribe()
        if hasattr(engine, "console_control_handler"):
            engine.console_control_handler.subscribe()
        app = self._bootstrap_app()
        try:
            if self.use_gevent:
                # Turn off autoreload when using *cgi.
                #cherrypy.config.update({‘engine.autoreload_on‘: False})
                addr = cherrypy.server.bind_addr
                cherrypy.server.unsubscribe()
                f = GeventWSGIServer(addr, app, log=None)
                s = servers.ServerAdapter(engine, httpserver=f, bind_addr=addr)
                s.subscribe()
                engine.start()
            else:
                cherrypy.quickstart(app)
        except KeyboardInterrupt:
            self.stop()
        else:
            engine.block()

    def stop(self):
        cherrypy.engine.stop()
时间: 2024-11-11 17:53:33

cherrypy & gevent patch的相关文章

Python gevent学习笔记

gevent是Python的一个用于网络IO的函数库,其中应用到了 coroutine(协同程序) 的思想.首先来了解下目前网络框架的几种基本的网络I/O模型: 阻塞式单线程:这是最基本的I/O模型,只有在处理完一个请求之后才会处理下一个请求.它的缺点是效能差,如果有请求阻塞住,会让服务无法继续接受请求.但是这种模型编写代码相对简单,在应对访问量不大的情况时是非常适合的. 阻塞式多线程:针对于单线程接受请求量有限的缺点,一个很自然的想法就是给每一个请求开一个线程去处理.这样做的好处是能够接受更多

[转载]python gevent

原地址: http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001407503089986d175822da68d4d6685fbe849a0e0ca35000 感谢廖雪峰老师. Python通过yield提供了对协程的基本支持,但是不完全.而第三方的gevent为Python提供了比较完善的协程支持. gevent是第三方库,通过greenlet实现协程,其基本思想是: 当一个g

小计使用多线程和gevent来提高celery性能及稳定性

前言: 有朋友问我,我那个任务队列是怎么实现,他的疑问其实主要是celery不支持多线程.先说说我那实现的方法,其实我的做法和celery.rq这样的框架很像的,都是把任务push到队列里面,然后pull取出任务而已,celery里面还可以取任务,我这个是通过传送uuid来实现的.   朋友问celery不支持多线程,那是他没有好好看文档.celery是支持多任务并发的,哎... 好好看文档呀. 原文:http://rfyiamcool.blog.51cto.com/1030776/153082

python Gevent – 高性能的Python并发框架

Gevent是一个基于greenlet的Python的并发框架,以微线程greenlet为核心,使用了epoll事件监听机制以及诸多其他优化而变得高效. 于greenlet.eventlet相比,性能略低,但是它封装的API非常完善,最赞的是提供了一个monkey类,可以将现有基于Python线程直接转化为greenlet,相当于proxy了一下(打了patch). 今天有空就迫不及待的试一下效果. 1.安装 Gevent依赖libevent和greenlet,需要分别安装. 1 2 3 4 5

流动python - 写port扫描仪和各种并发尝试(多线程/多进程/gevent/futures)

port扫描仪的原理非常easy.没有什么比操作更socket,能够connect它认为,port打开. import socket def scan(port): s = socket.socket() if s.connect_ex(('localhost', port)) == 0: print port, 'open' s.close() if __name__ == '__main__': map(scan,range(1,65536)) 这样一个最简单的端口扫描器出来了. 等等喂,半

什么是猴子补丁(monkey patch)

monkey patch指的是在运行时动态替换,一般是在startup的时候. 用过gevent就会知道,会在最开头的地方gevent.monkey.patch_all();把标准库中的thread/socket等给替换掉.这样我们在后面使用socket的时候可以跟平常一样使用,无需修改任何代码,但是它变成非阻塞的了. 之前做的一个游戏服务器,很多地方用的import json,后来发现ujson比自带json快了N倍,于是问题来了,难道几十个文件要一个个把import json改成import

17、第七周-网络编程 - 协程概念介绍、协程gevent模块并发爬网页

协程,又称微线程,纤程.什么是线程:协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈.因此:协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置. 协程的好处: 无需线程上下文切换的开销 无需原子操作锁定及同步的开销(注解:"原子操作(atomic operation)是不需要synchr

python的猴子补丁monkey patch

monkey patch指的是在运行时动态替换,一般是在startup的时候. 用过gevent就会知道,会在最开头的地方gevent.monkey.patch_all();把标准库中的thread/socket等给替换掉.这样我们在后面使用socket的时候可以跟平常一样使用,无需修改任何代码,但是它变成非阻塞的了. 一个比较实用的例子,很多代码用到 import json,后来发现ujson性能更高,如果觉得把每个文件的import json 改成 import ujson as json成

gevent 协程 使用

Python通过yield提供了对协程的基本支持,但是不完全.而第三方的gevent为Python提供了比较完善的协程支持. gevent是第三方库,通过greenlet实现协程,其基本思想是: 当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行.由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO. 由于切换是在IO操作时自动完成,