V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
aljun
V2EX  ›  Python

基于 Gevent,撸了一个 web 框架的轮子

  •  
  •   aljun · 2016-05-06 22:05:50 +08:00 · 7843 次点击
    这是一个创建于 3121 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这是楼主的第一个上交到 pypi 的项目,项目名字叫 Jolla 是一个基于 gevent 的高性能 API server

    这里是 gevent 所有的特性(来自 gevent 的文档):

    • 基于 libev 的高速的 event loop(epoll on Linux,kqueue on freeBSD)
    • 轻量执行的 greenlet
    • 还能更好的使用 Python 标准库的 API (被 gevent 猴子补丁后)
    • Cooperative sockets with SSL support.
    • DNS queries performed through threadpool or c-ares.
    • Monkey patching utility to get 3rd party modules to become cooperative.

    以上这些特性,都被 Jolla 继承了

    Jolla 也拥有以下独特的特性

    • 自己的精简好用的路有系统
    • 简单快速的 json response
    • 简单而且简短的项目结构
    • 自己的错误处理方式

    当我在写 Jolla 时,想写的是一个高性能的 API server ,它能让使用者以简短而简短的规则去完成 server 的工作,能让他们把她们的计算过程也好运算也好,快速的发到浏览器或移动端,所以我把 Jolla 写的尽可能简单。

    项目地址在这 http://salamer.github.io/jolla/ 项目文档教程在这 https://github.com/salamer/jolla/wiki

    如果有什么不对的,或是错误的地方,欢迎指点,如果觉得好,可以 star 一下,谢谢啦~

    安装是:

    pip install jolla
    

    使用绝对简单:

    
    from jolla import WebApp,jolla_server,render
    
    def index(request):
        return render('index.html')
    
    class app(WebApp):
        urls=[
            (r'/',index)
        ]
    
    if __name__=="__main__":
        server=jolla_server(app)
        server.run_server()
        
    

    (之前在 v 站发错节点了)

    55 条回复    2017-01-09 20:30:41 +08:00
    kindjeff
        1
    kindjeff  
       2016-05-06 22:22:07 +08:00
    支持啊,这周末我来试试
    aljun
        2
    aljun  
    OP
       2016-05-06 22:32:39 +08:00
    @kindjeff 好啊,= =+
    2225377fjs
        3
    2225377fjs  
       2016-05-06 22:47:49 +08:00
    gevent 不是 自己有 wsgi server 么。。?楼主这是个 搞了个 wsgi application 上去。。?其实把 gevent 的 wsgiserver 能和现在大多数的 python web 框架结合起来用的。
    aljun
        4
    aljun  
    OP
       2016-05-06 23:01:13 +08:00
    @2225377fjs 基本上是包装了 gevent 的 pywsgi (非 wsgi ),给日常更简单的使用,
    Magic347
        5
    Magic347  
       2016-05-06 23:18:30 +08:00
    https://github.com/salamer/jolla/blob/master/jolla/session.py
    Bug Report : empty()函数逻辑写反了
    aljun
        6
    aljun  
    OP
       2016-05-06 23:23:14 +08:00
    @Magic347 好,改改改!多谢查看
    Magic347
        7
    Magic347  
       2016-05-06 23:25:59 +08:00
    @aljun 赞 fix 效率!
    tabris17
        8
    tabris17  
       2016-05-06 23:27:35 +08:00
    类似 flask 么
    ipconfiger
        9
    ipconfiger  
       2016-05-06 23:32:54 +08:00
    用 flask 写好的东西,用 gunicorn 也可以加持 gevent 嘛,何必呢
    kindjeff
        10
    kindjeff  
       2016-05-06 23:37:03 +08:00
    session.py 第 47 行没有设置 value 值时返回 false 吗,还是故意这么写的
    aljun
        11
    aljun  
    OP
       2016-05-06 23:37:10 +08:00
    @tabris17 比 flask 要简单, flask 是 web 框架,我这是做 API server
    aljun
        12
    aljun  
    OP
       2016-05-06 23:39:14 +08:00
    @kindjeff bug fixed!
    aljun
        13
    aljun  
    OP
       2016-05-06 23:42:06 +08:00
    @ipconfiger 就是简单点呗,我当时是想搞个怎么简单怎么来的,但又完全能应付一些业务那种
    justfly
        14
    justfly  
       2016-05-07 00:54:12 +08:00
    Server 的 方法 run_server 不妨改为 run 。读起来更舒服,不啰嗦。
    ayaseangle
        15
    ayaseangle  
       2016-05-07 01:12:05 +08:00 via Android
    貌似不错。。
    Owenjia
        16
    Owenjia  
       2016-05-07 02:11:46 +08:00 via Android
    表示现在在用 pycnic ,跟这个挺像的。
    mirrosite
        17
    mirrosite  
       2016-05-07 08:36:13 +08:00
    return 应该返回数据,而不是返回 render 模板
    Allianzcortex
        18
    Allianzcortex  
       2016-05-07 09:34:57 +08:00
    每次看到 LZ 都感觉自己大学白过了一样……
    julyclyde
        19
    julyclyde  
       2016-05-07 09:52:48 +08:00
    把框架和 IO 库合起来并不好吧?
    aljun
        20
    aljun  
    OP
       2016-05-07 10:30:39 +08:00 via iPhone
    @Owenjia 有点类似,不过我直接把 gevent 的弄出来,要比它使用简单的多,你只需写个路由,别的都爱怎么搞怎么搞
    aljun
        21
    aljun  
    OP
       2016-05-07 10:31:02 +08:00 via iPhone
    @mirrosite 这个怎么说呢?求赐教
    aljun
        22
    aljun  
    OP
       2016-05-07 10:31:16 +08:00 via iPhone
    @julyclyde 并没有 io 库呀
    aljun
        23
    aljun  
    OP
       2016-05-07 10:31:30 +08:00 via iPhone
    @Allianzcortex 啊?为什么?
    Owenjia
        24
    Owenjia  
       2016-05-07 11:00:57 +08:00 via Android
    @aljun
    我个人更喜欢应用和服务器分开,现在在用 gunicorn ,代码里只写些逻辑之类的,然后写好应用直接用它运行。
    aljun
        25
    aljun  
    OP
       2016-05-07 11:03:50 +08:00 via iPhone
    @Owenjia 当时的想法就是,现在要是有一个计算的后端要求,然后需要提供服务,那就把心思放在计算上,然后极为简单的使用 Jolla 扔上去就好,所以我才用的 gevent 的 pywsgi ,性能我测试结果还是很不错的
    mengzhuo
        26
    mengzhuo  
       2016-05-07 11:04:38 +08:00 via iPhone
    楼主的代码太复杂了…
    可以看看我的项目 json rpc
    https://github.com/mengzhuo/justrpc
    xxr3376
        27
    xxr3376  
       2016-05-07 11:09:57 +08:00
    楼主你的 git commit log 实在是太过于混乱了。。。各种 update 不知道在干吗,以及翻看了一下以前的项目发现一屏幕“~~~~”。。。

    本来想看看代码精妙之处的,不过看着实在太累。。
    Owenjia
        28
    Owenjia  
       2016-05-07 11:12:17 +08:00 via Android
    @aljun
    gevent 我也在用啦,性能确实不错。我的意思只是把运行方式独立出来,就是把你例子里的最后那几行单独作为一个命令拿出来。
    原本需要 python foo.py 这样运行,用 gunicorn 就是 gunicorn foo:app 这样运行,代码里不需要涉及任何运行用的语句,只是 wsgi 应用。
    xxr3376
        29
    xxr3376  
       2016-05-07 11:16:00 +08:00
    @Owenjia 支持,为了极其不明显的性能优化把代码的复杂度提升了一个等级完全得不偿失。

    顺便看了看代码,一屏幕的

    {{
    try:
    self.request['cookies'] = self._environ['HTTP_COOKIE']
    except KeyError:
    self.request['cookies'] = None
    }}

    为啥不直接 self.request['cookies'] = self._environ.get('HTTP_COOKIE', None) 呢。。
    aljun
        30
    aljun  
    OP
       2016-05-07 11:16:36 +08:00 via iPhone
    @xxr3376 当年不懂事啊⋯⋯现在开始认真对待 github 了,我 commit 时应该有写 update 啥的吧
    aljun
        31
    aljun  
    OP
       2016-05-07 11:17:34 +08:00 via iPhone
    @xxr3376 当时觉得看着蛮喜欢⋯⋯就这样写了,嗯嗯,这种规范问题以后注意
    xxr3376
        32
    xxr3376  
       2016-05-07 11:18:16 +08:00
    @aljun 比如 gevent 的 WSGI IO 库( gevent ), parse query_string 的 urlparse 标准库已经有了。。为何你还要重新造轮子,更何况你的 query_string parser 写的不对。。
    aljun
        33
    aljun  
    OP
       2016-05-07 11:18:21 +08:00 via iPhone
    @Owenjia 嗯,好,我再想想看看,能不能做成这么优化
    aljun
        34
    aljun  
    OP
       2016-05-07 11:19:36 +08:00 via iPhone
    @xxr3376 好,回去改改,
    xxr3376
        35
    xxr3376  
       2016-05-07 11:20:27 +08:00
    @aljun update 没有啥语义,同样是 update 有的时候是更新了下版本号,有的时候随便改了点别的。
    在公司里一般都会用 http://www.ruanyifeng.com/blog/2016/01/commit_message_change_log.html 这类的 commit log ,否则 review 你的 commit 会超费时间。。
    xxr3376
        36
    xxr3376  
       2016-05-07 11:23:01 +08:00   ❤️ 1
    @aljun 作为一个 library ,不应该用 print ,而是应该用标准的 logging 。用户可以用 logging scope 去自由的选择要不要看到你的提示。

    raise HTTP404Error ,作为一个框架应该是 HTTPStatusError(404),这样就能支持任意的 HTTP Error 了。
    minsheng
        37
    minsheng  
       2016-05-07 11:23:46 +08:00 via iPhone
    看到 Jolla 突然想知道是什么意思,为什么莫名让我想起了墨西哥边上的一座城市
    bwangel
        38
    bwangel  
       2016-05-07 11:24:43 +08:00
    额,看到你项目里面刷 PR 的。。。

    这个真是。。。。
    xxr3376
        39
    xxr3376  
       2016-05-07 11:24:48 +08:00
    @aljun 看到了 parse 里面居然是每次临时 compile regex 的。。同学你的高性能去哪里了。。
    aljun
        40
    aljun  
    OP
       2016-05-07 11:25:03 +08:00 via iPhone
    @xxr3376 嗯,好的,受教了,因为这是第一个拿出来做库的项目,多多不注意请谅解,我回去在思考一下优化下设计上不合理的地方
    aljun
        41
    aljun  
    OP
       2016-05-07 11:26:04 +08:00 via iPhone
    @bwangel 朋友看到了就⋯⋯大家一起玩玩呗,嘻嘻
    aljun
        42
    aljun  
    OP
       2016-05-07 11:26:53 +08:00 via iPhone
    @minsheng 偶然想起的一个音,我就拼音化了,就拿来做名字了
    aljun
        43
    aljun  
    OP
       2016-05-07 11:28:08 +08:00 via iPhone
    @xxr3376 不,那里只 compile 了一次,之前设计不好,算是补坑,但是只用做一次 re 的
    xxr3376
        44
    xxr3376  
       2016-05-07 11:38:22 +08:00
    @aljun 看了许多遍。。都觉得你是每个请求都把每个 url_pattern compile 一次的。。。看的好心累。。。
    lianghui
        45
    lianghui  
       2016-05-07 11:43:15 +08:00
    项目看了,比我当年毕业时强很多了。说说你的的项目的问题: app 应用层异常 exception ( 500 internal exception )没有做特别的处理 貌似扔给 wsgiserver 去处理了,处理了 404 状态, 403 状态处理缺乏, chunk encoding 处理缺乏。 utf8 编码处理没有考虑,问题比较多。 建议楼主看看 webob 这个项目,或者 cherrypy 这种古董。


    其他问题:

    log 没有,别用 print
    基建功能做好单元测试

    代码建议:

    所有的功能函数,类,方法必须加上注释,哈哈这个很难,不过坚持就好,我给公司的项目和小组都是这样严格要求的。

    使用好的 ide 工具可以帮助你加快编码,减少注释带来的烦恼,忘词等(使用 java 一年得到的真谛)。
    mengzhuo
        46
    mengzhuo  
       2016-05-07 11:55:54 +08:00 via iPhone
    @aljun 路由要用前缀树
    aljun
        47
    aljun  
    OP
       2016-05-07 16:08:02 +08:00 via iPhone
    @mengzhuo 好,下次更新时试试,这个用的正则
    aljun
        48
    aljun  
    OP
       2016-05-07 16:08:24 +08:00 via iPhone
    @lianghui 多谢建议,受教了,
    aljun
        49
    aljun  
    OP
       2016-05-07 18:41:31 +08:00 via iPhone
    @xxr3376 晚点写点注释好了⋯⋯之前太懒了⋯⋯
    julyclyde
        50
    julyclyde  
       2016-05-07 22:30:32 +08:00
    @aljun io 库是 gevent 啊
    aljun
        51
    aljun  
    OP
       2016-05-07 23:35:47 +08:00 via iPad
    @julyclyde 这样啊,,网络么,,,我当时就是决定不分开的, Jolla 只是简单,可用,不做过多
    icybee
        52
    icybee  
       2016-05-07 23:47:48 +08:00
    cool 。。。。
    aljun
        53
    aljun  
    OP
       2016-05-07 23:49:39 +08:00 via iPad
    @icybee 嘻嘻
    aljun
        54
    aljun  
    OP
       2016-06-03 20:49:51 +08:00 via iPad
    挖个坟,因为更新
    EchoUtopia
        55
    EchoUtopia  
       2017-01-09 20:30:41 +08:00
    赞一个
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   990 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 21:15 · PVG 05:15 · LAX 13:15 · JFK 16:15
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.