eventlet dbpool for postgresql &mysql
时间:2010-10-06 来源:lexus
并发编程利器Eventlet
Eventlet是由第二人生(Secondlife)开源的高度伸缩性的Python网络编程库.根据官方介绍大致特性如下:
- 非阻塞I/O模型
- 协程(Coroutines)使得开发者可以采用阻塞式的开发风格,却能够实现非阻塞I/O的效果
- 隐式事件调度,使得可以在Python解释器或者应用程序的某一部分去使用Eventlet
关于协程,大致可以理解成允许子程序可以多次暂停和恢复执行,是实现多任务的一种有效手段,具体见这里
在Python的世界里,实现了nonblocking I/O的产品并不算少.比如内置的Asyncore和著名的Twisted.相比之下,Eventlet是更容易上手和使用的。
举个例子
import eventlet
pool = eventlet.GreenPool()
while True: pool.spawn(func,args)
上面这段代码,几乎就是使用eventlet的范式:
Eventlet内置提供了一个基于上述原理实现的数据库连接池,目前仅支持MySQL和PostgreSQL.为了测试其性能如何,我参考了gashero的这篇文章,并简化了测试方案.
测试对象分别是MySQLdb(MySQL驱动的Python封装),Eventlet.db_pool,DBUtils
测试代码如下:
pool = eventlet.GreenPool()
while True: pool.spawn(func,args)
上面这段代码,几乎就是使用eventlet的范式:
- GreenPool 用来实现协程,保证并行;
- Spawn 用来调用相应的函数,完成具体业务.
Eventlet内置提供了一个基于上述原理实现的数据库连接池,目前仅支持MySQL和PostgreSQL.为了测试其性能如何,我参考了gashero的这篇文章,并简化了测试方案.
测试对象分别是MySQLdb(MySQL驱动的Python封装),Eventlet.db_pool,DBUtils
测试代码如下:
import time
import random
import MySQLdb
import eventlet.db_pool as db_pool
from DBUtils.PooledDB import PooledDB
conn_kwargs={'host':'192.168.8.84','user':'root','passwd':'','db':'logs'}
sql="""SELECT * FROM test WHERE id=%d"""
pooled=db_pool.ConnectionPool(MySQLdb,**conn_kwargs)
pooldb=PooledDB(MySQLdb,**conn_kwargs)
def query(conn):
cur=conn.cursor()
cur.execute(sql%(random.randint(1,1000)))
data=cur.fetchall()
return cur
def print_now():
print time.strftime("%H:%M:%S")
return
def test1(times):
print_now()
for i in range(0,times):
conn=MySQLdb.connect(**conn_kwargs)
r = query(conn)
r.close()
conn.close()
print_now()
return
def test2(times):
print_now()
for i in range(0,times):
conn=pooled.get()
try:
query(conn)
finally:
pooled.put(conn)
print_now()
return
def test3(times):
print_now()
for i in range(0,times):
conn=pooldb.connection()
r=query(conn)
r.close()
conn.close()
print_now()
return
然后进入Python解释器交互环境
import random
import MySQLdb
import eventlet.db_pool as db_pool
from DBUtils.PooledDB import PooledDB
conn_kwargs={'host':'192.168.8.84','user':'root','passwd':'','db':'logs'}
sql="""SELECT * FROM test WHERE id=%d"""
pooled=db_pool.ConnectionPool(MySQLdb,**conn_kwargs)
pooldb=PooledDB(MySQLdb,**conn_kwargs)
def query(conn):
cur=conn.cursor()
cur.execute(sql%(random.randint(1,1000)))
data=cur.fetchall()
return cur
def print_now():
print time.strftime("%H:%M:%S")
return
def test1(times):
print_now()
for i in range(0,times):
conn=MySQLdb.connect(**conn_kwargs)
r = query(conn)
r.close()
conn.close()
print_now()
return
def test2(times):
print_now()
for i in range(0,times):
conn=pooled.get()
try:
query(conn)
finally:
pooled.put(conn)
print_now()
return
def test3(times):
print_now()
for i in range(0,times):
conn=pooldb.connection()
r=query(conn)
r.close()
conn.close()
print_now()
return
然后进入Python解释器交互环境
Python -i db-pool-test.py
>>> test1(10000) //MySQLdb
16:04:34
16:11:25
>>> test2(10000) //Event
16:12:35
16:15:22
>>> test3(10000) //DBUtils
16:15:28
16:18:09
总体来看,和传统的MySQLdb相比,性能有了很大的提升,和DBUtils差别并不是很明显.
协程凶猛啊! Posted by Guang Feng at 3:02 AM Labels: 子曾经曰过
>>> test1(10000) //MySQLdb
16:04:34
16:11:25
>>> test2(10000) //Event
16:12:35
16:15:22
>>> test3(10000) //DBUtils
16:15:28
16:18:09
总体来看,和传统的MySQLdb相比,性能有了很大的提升,和DBUtils差别并不是很明显.
协程凶猛啊! Posted by Guang Feng at 3:02 AM Labels: 子曾经曰过
2 comments:
s7v7nislands said...不知道你的mysql服务器有没有开query cache,如果开了感觉这样的结果不是很科学。你有没有考虑过select语句的结果被服务器cache的,所以后面运行时cache命中率较高。
May 18, 2010 6:39 AM Guang Feng said...嗯嗯,说的很对,不过我测试的时候 关掉了cache
June 10, 2010 7:34 PM
Post a Comment
Newer Post Older Post Home
相关阅读 更多 +