為Python加速

來源:互聯網
上載者:User
本來我一直不知道怎麼來更好地最佳化網頁的效能,然後最近做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了)

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.