为Python加快 – python+memcached
原来我一直不知道怎么来更好地优化网页的机能,然后最近做python和php同类网页渲染速度较量时,意外地发明一个很简朴很呆子可是 我一直没发明的好要领(不得不BS我本身):直接像某些php应用好比Discuz论坛那样,在生成的网页中打印出“本页面生成时间几多几多秒”,然后在 不断地会见网页测试时,很直观地就能发明什么操纵会导致瓶颈,奈何来办理瓶颈了。
于是我发明SimpleCD在 生成首页时,意外地竟然需要0.2秒阁下,真真不能忍:比拟Discuz论坛首页平均生成才0.02秒,而Discuz论坛的首页页面无疑比 SimpleCD的主页要巨大不少;这让我情何故堪啊,因为这一定不是Python语言导致的差距,只能说是我完全没做优化而Discuz措施优化得很好 的效果。
其实不消阐明也能知道必定是数据库在拖累,SimpleCD在生成首页时需要在sqlite的三个数据库中举办42多次查询,是汗青原因导致的极其低效的一个设计;可是这40多次查询中,其实大部门长短常快的查询,仔细阐明一下就有两个是机能大户,其他都不慢。
第一个大户就是:获取数据个数
SELECT count(*) FROM verycd
这个操纵每次都要花不少时间,这是因为每次数据库都要锁住然后遍历一遍主键统计个数的缘故,数据量越大耗时就越大,耗时为O(N),N为数据库巨细;实际 上办理这个问题很是容易,只要随便在哪存一个当前数据的个数,只有在增删数据的时候窜改就行了,这样时间就是O(1)的了
第二个大户就是:获取最新更新的20个数据列表
SELECT verycdid,title,brief,updtime FROM verycd ORDER BY updtime DESC LIMIT 20;
因为在updtime上面做了索引,所以其实真正查询时间也就是搜索索引的时间罢了。然则为什么这个操纵会慢呢?因为我的数据是凭据publish time插入的,按update time举办显示的话就必定需要在至少20个差异的处所做I/O,这么一来就慢了。办理的要领就是让它在一个处所做I/O。也就是,除非数据库插手新数据 /改变原有数据,不然把这条语句的返回功效缓存起来。这么一来又快了20倍:)
接下来的是20条小case:取得宣布人和点击数信息
SELECT owner FROM LOCK WHERE id=XXXX; SELECT hits FROM stat WHERE id=XXXX;
这里为什么没用sql的join语句来省点事呢?因为架构原因这些数据放在差异的数据库里,stat是点击率一类的数据库,因为需要频繁的插入所以用 mysql存储;而lock和verycd是需要大量select操纵的数据库,因为mysql悲剧的索引利用环境和分页效率而存放在了sqlite3数 据库,所以无法join -.-
总之这也不是问题,跟适才的办理要领一样,统统缓存
所以纵观我这个例子,优化网页机能可以一言以蔽之,缓存数据库查询,即可。我相信大部门网页应用都是这样:)
终于轮到memcached了,既然规划缓存,用文件做缓存的话照旧有磁盘I/O,不如直接缓存到内存内里,内存I/O可就快多了。于是memcached顾名思义就是这么个东东。
memcached是很强大的东西,因为它可以支持漫衍式的共享内存缓存,大站都用它,对小站点来说,只要出得起内存,这也是好对象;首页所需要的内存缓冲区巨细预计不会高出10K,更况且我此刻也是内存土豪了,还在乎这个?
设置运行:因为是单机没啥好配的,改改内存和端口就行了
vi /etc/memcached.conf /etc/init.d/memcached restart
在python的网页应用中利用之
import memcache mc = memcache.Client(['127.0.0.1:11211'], debug=0)
memcache其实就是一个map布局,最常利用的就是两个函数了:
第一个就是set(key,value,timeout),这个很简朴就是把key映射到value,timeout指的是什么时候这个映射失效
第二个就是get(key)函数,返回key所指向的value
于是对一个正常的sql查询可以这么干
sql = 'select count(*) from verycd' c = sqlite3.connect('verycd.db').cursor() # 本来的处理惩罚方法 c.execute(sql) count = c.fetchone()[0] # 此刻的处理惩罚方法 from hashlib import md5 key=md5(sql) count = mc.get(key) if not count: c.execute(sql) count = c.fetchone()[0] mc.set(key,count,60*5) #存5分钟
个中md5是为了让key漫衍更匀称,其他代码很直观我就不表明白。
优化过语句1和语句2后,首页的平均生成时间已经低落到0.02秒,和discuz一个量级了;再颠末语句3的优化,最终功效是首页生成时间低落到了0.006秒阁下,颠末memcached寥寥几行代码的优化,机能提高了3300%。终于可以挺直腰板来看Discuz了)