对于数字运算任务,你可以使用 PyPy 的即时编译功能。你也可以使用 Numpy 的测试套,它已经通过 C 语言扩展进行了全面的升级。今年(2017年)后季,PyPy 有望与 Python 3.5 达到一致。
以上所有的这些伟大的工作都激发了我在 Python 被广泛应用的领域中进行一番创新,即 web 和微服务开发。
走进 Japronto
Japronto 是一个全新的微框架,它是为你的微服务量身打造的。它的主要目标是: 速度快、可扩展、轻量级。它可以通过 asyncio 来进行同步与异步编程。它真的很快,甚至快过 NodeJS 和 Go.
私信菜鸟007有神秘惊喜哦!
不同框架的相应速度对比
勘误:
正如 @heppu 指出的那样,如果我们在编写代码时更注意点的话,Go 语言的 HTTP 库会比图表中的速度更快 12%
左右。同时,以本文的比较标准,Go 语言中有一个 fasthttp 库,其速度只比 Japronto 差 18%。
详细的内容请参阅下面的两篇文章。
https://github.com/squeakypl/japronto/pull/12 和 https://github.com/squeakypl/japronto/pull/14
从上表中我们可以看到,
Meinheld WSGI 的速度堪比 NoneJS 和 Go。虽然其包含了固有的阻塞设计,但是它的速度依旧远超前四个框架,这四个框架都是
Python 异步解决方案。所以,不要相信所谓的异步系统一定快的谬论。尽管它们是并发执行的,但是除了并发还有很多其他的东西要考虑。
虽然我只是使用了简单的 “Hello world” 应用程序来测试这些微框架,但是这足以清晰展示许多解决方案在服务框架上的开销。
上述测试结果都是基于在圣保罗地区推出的
AWS c4.2Xlarge 实例,该实例有 8 个虚拟 CPU 中心,自带默认的共享租赁、HVM 虚拟化和磁盘存储。 这台机器上的的系统是
Ubuntu 16.04.1 LTS(Xenial Xerus),搭载 Linux 4.4.0–53-generic x86_64 内核。使用的
CPU 是 Xeon® CPU E5–2666 v3 @ 2.90GHz CPU。我使用的是从源代码编译出来的 Python 3.6。
公平起见,其他所有的“竞争者”,包括 Go 语言,都使用单进程模式。 使用 wrk 来加载测试服务, 一个线程, 100 个链接, 每个链接有 24 个同时的请求(pipelined),总计 2400 个平行请求。
HTTP 管道化图示(图片来自维基)
在 Japronto 中, HTTP 管道是非常重要的,因为当它处理请求时,管道是一种优化方法。
大多数服务器以非管道化的方式处理管道式请求。他们也不想着去优化这一点(实际上, Sanic 和 Meinheld 会背地里偷偷删除那些来自管道式客户端的请求,这违反了 HTTP 1.1 协议)。
简单来说,管道是一项技术,依靠它,在同一个 TCP 连接中,客户端不必等待接受上一次的请求响应后再发送下一个请求。为了保持整个通讯过程的完整性,服务器会以与请求相同的顺序返回响应。
具体的优化细节
当客户端使用管道将很多小型的 GET 请求一起发送的时候,在服务器端,这些请求则很有可能会落在同一个 TCP 包中,然后会被一次系统调用同时读入。
在系统调用中,与数据在进程内空间的转移相比,将数据从内核空间转移用户空间是非常耗时的。这也是为什么尽可能少进行系统调用的原因。
当
Japronto
接收数据并成功从中解析多个请求后,它会尝试尽快执行所有请求,以正确的顺序粘合响应,然后使用一次系统调用进行回写。实际上,如果使用了
scatter/gather IO 系统调用,则可以在粘合过程中使用内核进行加速,但是 Japronto 暂时还没使用这项系统调用。
请注意,上述的快速处理流程可能不总会被实现,因为有一些请求特别长,等待它们会无端增加很多不必要的延时。
当具体实现处理时务必要格外的小心,你需要考虑系统调用的时间与接受完整请求的时间。
进群:864573496 自行下载教程哦!
Japronta 使用插值法,从连续分组数据中计算第 50 位百分比,给出中值为 1,214,440 RPS
除了对管道客户端请求的延时写入外,代码还采用了其他几项技术:
Japronto 几乎是由 C 语言完成的,其分析器,协议,连接处理器,路由,请求以及响应都被写为了 C 扩展代码。
除非明确需要,Japronto 极力推迟创建与之内部结构对应的 Python 对象。例如,直到需要显示时,首部字段字典才会被创建。所有的字段边界会被提前标记,但是只有当第一次调用的时候,首部键值的标准化与字符串对象的创建才会真正完成。
Japronto
使用由 C 语言编写的且性能卓越的 picohttpparser 解析器来解析状态码,首部字段以及分块的 HTTP 报文实体。
picohttpparser 使用现代 CPU 的文本处理指令和 SSE4.2 扩展来快速的实现 HTTP 字段边缘的匹配。I/O
操作则由性能超好的 uvloop 实现,它本身就是 libuv 的一个封装。在底层,这提供了读写就绪异步通知的 epoll 系统调用的桥梁,