当前位置:编程学习 > python >>

Python 和 PHP 的 Web 服务器性能测试

 

原始出处:keakon的涂鸦馆

 

这几天一直在玩虚拟机,测了几种Python和PHP的Web服务器的性能,顺便记录下来。

 

测试环境:

 

宿主:MacBook Pro MC700

操作系统:Mac OS X 10.6.8

CPU: 2.3GHz Intel Core i5(双核)

内存:4 GB

 

虚拟机:Virtual Box

操作系统:Linux version 2.6.32-5-686 (Debian 2.6.32-35)

CPU: 限制到40%宿主CPU,单核(2.3 * 40% = 0.92GHz)

内存:128 MB

 

数据库:MySQL 5.5.15(基本上是用small配置,禁用了InnoDB以节省内存)

 

Python:2.6.6

gevent:1.0a2

uWSGI:0.9.9.1

Tornado:2.0

amysql (for gevent):2011-09-02(无版本号,只能按更新日期来算。支持MySQL 5.1,MySQL 5.5不能完全通过所有测试,但本文所用的测试没问题。)

MySQL for Python:1.2.3

 

PHP:5.3.8-1

spawn-fcgi:1.6.3

nginx:1.0.6

 

Hello world就不列出了,4个都差不多,大致是PHP > uWSGI > gevent > Tornado。

这里主要模拟比较现实的使用。

准备一个数据表,引擎为MyISAM,字段为id(主键),value(浮点数),随机生成100万条数据插入。

访问前执行“SET GLOBAL query_cache_size = 0;”,禁用查询缓存。

每次访问时生成1~999990之间的随机数r,查询id为r~r+10之间的行,将value相加。重复这个操作10次,即访问10次数据库。最后把这个结果输出,值应该在50左右。

因为是单CPU,所以都只采用1个处理进程。

在宿主上用ab -c 100 -n 1000来测试(100并发,共1000请求)。

 

数据库启动后约剩80MB内存,执行完一次测试后剩40MB,有60多MB缓存。

 

先是gevent,用amysql的同步方式查询:

 

from gevent.pywsgi import WSGIServer

import amysql

from random import randint

 

con = amysql.Connection()

con.connect ('127.0.0.1', 3306, 'root', '123', 'test')

con.query('SET GLOBAL query_cache_size = 0;')

  

def application(env, start_response):

    sum = 0

    for i in xrange(10):

        r = randint(1, 1000000 - 10)

        rs = con.query('SELECT value FROM test WHERE id >= %s LIMIT 10;', (r,))

        for j in rs.rows:

            sum += j[0]

    start_response('200 OK', [('Content-Type','text/plain')])

    return ['%6f' % sum]

  

if __name__ == '__main__':

    WSGIServer(('', 8089), application).serve_forever()

 

启动占用6.8MB内存,测试完占用8.3MB。

结果为154 QPS(每秒处理154个请求),无失败请求。

 

gevent + amysql的异步方式:

 

import gevent

from gevent.pywsgi import WSGIServer

import amysql

from random import randint

 

con = amysql.Connection()

con.connect ('127.0.0.1', 3306, 'root', '123', 'test')

con.query('SET GLOBAL query_cache_size = 0;')

 

def query(r):

    return con.query('SELECT value FROM test WHERE id >= %s LIMIT 10;', (r,))

  

def application(env, start_response):

    sum = 0

    queries = []

  

    for i in xrange(10):

        r = randint(1, 1000000 - 10)

        queries.append(gevent.spawn(query, r))

 

    for q in queries:

        rs = q.get()

        for j in rs.rows:

            sum += j[0]

            pass

    start_response('200 OK', [('Content-Type','text/plain')])

    return ['%6f' % sum]

  

if __name__ == '__main__':

    WSGIServer(('', 8088), application).serve_forever()

 

结果为149 QPS,无失败请求。看来在并发足够多时,异步没有帮助,反而因为要执行更多代码而变慢了。

 

gevent + MySQL for Python:

 

from gevent.pywsgi import WSGIServer

import MySQLdb

from random import randint

 

con = MySQLdb.connect(user='root', passwd='123', db='test')

cu = con.cursor()

cu.execute('SET GLOBAL query_cache_size = 0;')

  

def application(env, start_response):

    sum = 0

    for i in xrange(10):

        r = randint(1, 1000000 - 10)

        cu.execute('SELECT value FROM test WHERE id >= %s LIMIT 10;', (r,))

        for j in cu.fetchall():

            sum += j[0]

    start_response('200 OK', [('Content-Type','text/plain')])

    return ['%6f' % sum]

  

if __name__ == '__main__':

    WSGIServer(('', 8087), application).serve_forever()

 

结果为122 QPS,无失败请求。这个库已经有1年多没更新了,看来已经不够给力了。

 

虽然测试是用的很快的主键查询,但我主要是测试访问数据库和处理响应的速度,数据库的性能不是我关注的重点。

可以看出amysql的同步方式是最好的,所以下面就只用它来测试。

 

uWSGI:

自带了HTTP服务器,因此直接运行“uwsgi -l 1000 --http :9090 --wsgi-file test.py &”即可。

因为数据库连接和生成application的代码都和第一个例子相同,只是无需运行server,就不重复列出了。

共2个进程,启动占用6.1+2MB,测试完占用6.2+2MB。

结果为134 QPS,无失败请求。很奇怪它的表现比hello world差很多,但内存控制还算不错,而且命令很方便。

 

Tornado:

 

import tornado.ioloop

import tornado.web

import amysql

from random import randint

 

con = amysql.Connection()

con.connect ('127.0.0.1', 3306, 'root', '123', 'test')

con.query('SET GLOBAL query_cache_size = 0;')

  

class MainHandler(tornado.web.RequestHandler):

    def get(self):

        sum = 0

        for i in xrange(10):

            r = randint(1, 1000000 - 10)

            rs = con.query('SELECT value FROM test WHERE id >= %s LIMIT 10;', (r,))

            for j in rs.rows:

                sum += j[0]

        self.write('%6f' % sum)

  

application = tornado.web.Application([

补充:Web开发 , Python ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,