最近處理的效能優化總結思考
按照常理,效能優化應該是屬於比較高階,處於專案中後期的工作了,但是如果實現不給力,在專案初期就可以遇到了。
很多人都嫌棄Python慢,個人認為他們之中90%都沒有資格這麼說,一方面,需要高效能的地方並不是每個專案都需要,另一方面,他們自己寫的程式碼爛的要死,才是罪魁禍首。
Python的程式碼可讀性非常好,利於開發和維護,是對開發者友好的語言。但如果程式碼寫成一團糟,沒有揚長避短,導致維護困難,開發新功能無處下手,效能又遇到瓶頸,這個時候又怪罪起Python或是框架來,可以說是愚蠢至極。
我為什麼要提上面這段呢?因為我在工作中不斷地印證了之前聽聞的一個說法。那就是,當一個專案重構後,程式碼量縮減,效能提升n倍,往往會被人們歸功於使用了新語言或是新框架。但這樣的理解是不對的,就算是使用同一種語言,同一種框架,在重構時,由於已經有了之前的積累,這些積累包括需求的深刻認識,弊端和bug的提前瞭解,以此為鑑,才能夠在之後的重構時,搭建起較好的架構實現。
如若不然,該挖的坑還會再挖一遍,該跳的坑還得再跳一次。不從以往吸取教訓,總結經驗,那麼永遠都不會有出頭之日。
最近我就做了一些效能優化工作,也正好是同一語言同一框架的優化。有些東西,雖然我們聽說了,記住了,但是如果沒有經歷過的話,總感覺會缺少些東西。在這次的優化工作中,一些東西不斷地從實際當中總結出來,又不斷地和以往的知識相互驗證,讓我感覺受益匪淺,有點融會貫通的感覺,包括上文和下文提到的東西,我都是深有感悟啊!這個時候一定要記錄下來,因為感性的認識,和最終能夠形成文字表達出來的認識也有不同,後者明顯對知識的掌握更深。類比做題容易,但是如果要給別人講清楚如何做題,那對人的要求就要更高了。
綜上啊,這就是經驗啊,只有見的多了,才算是身經百戰。。。
下面談談詳細情況。
有些東西是可以立即採用的,比如非同步、cache。
非同步的作用無疑是非常大的。首頁載入慢?運營人員抱怨後臺大批量操作時頁面卡住?那這個時候就要考慮處理流程裡面都必須要使用者等在那裡嗎,使用者需要立刻就看到結果嗎?在書上,我們經常看到發郵件這種操作會被作者舉例,說是非常適合非同步。同樣,進首頁的時候判斷使用者參與了哪些活動,是否需要發紅包,運營審批一些後臺資料,這些操作都可以非同步實現,對結果沒影響,還顯著提升頁面載入和後臺審批速度。
並且,非同步處理可以使用多個worker,進一步減少處理時間。
目前我們公司非同步處理很複雜,大類可分為Redis佇列和Celery處理,其中內部還有細分,我認為這部分能夠重構一下,拋棄Redis,統一使用Celery。
cache,譯作快取,也譯作快取,實際上這是它的一體兩面。什麼東西很長時間不會變,什麼東西不需要立即對資料庫進行寫入,這些東西統統可以使用cache。
cache不單單指使用NoSql資料庫。其實在程式碼裡面就可以實現某些東西,比如有一個值是從資料庫中讀取的,但是基本不會改變,那這個時候可以使用@cache_property
來將這個值作為類的屬性快取起來。這樣的話,當程式啟動後(有些場景是第一次訪問請求時,比如使用odoo會在第一個訪問請求到來時建立url_mapping,會將對應的endipoint儲存,endpoint中即是處理對應url的類的例項),就會快取到記憶體中(和NoSql同樣是記憶體!),缺點是萬一要是值有改變的話,得重啟才行。
還有的,當然就是使用NoSql資料庫了,我們這邊用的是Redis。最近我看了一些《Redis應用實踐》,發現其中對Redis的使用非常主動:並不是所有資料都要存放到關係型資料庫中,NoSql只是一種輔助,而是將非常多的資料,比如說是涉及到經常改變的資料,直接放到Redis中進行處理,而永久化資料並沒有提及。非常遺憾的是,我們公司目前還沒有這種做法或是想法。
我們公司已經實現了兩套快取機制,但由於odoo的ORM寫入機制,儲存到Redis中的資料還沒怎麼使用呢,就經常被重寫,結果導致了非常嚴重的死鎖,所以都廢棄掉了。
目前的話我們只是在程式碼裡零星地使用Redis進行快取,可以說不怎麼正常。做優化時,我的程式碼實現還非常土,同樣的語句寫了好幾遍,被CTO和一位架構師同時吐槽,但目前也沒有時間去優雅處理。。。
以前一直沒感覺NoSql有多神,直到最近我才深深地理解了什麼叫做“儲存在記憶體中”的含義——硬碟就算是SSD,關係型資料庫也還是慢,對放在記憶體裡的資料實在是太快了。
以上這兩點的話,只要能夠理清楚實現邏輯就可以動手做改變了,但接下來的一些優化需要有能夠定量的指標才行。
關於Python程式碼的執行時間,我推薦使用line_profiler,它可以按行標註執行時間,比較好用。其他的很多都是按函式來標註,不太符合我們的需求。
按照line_profiler提供的每行執行時間,以及每行呼叫次數,可以很輕鬆的找出瓶頸。無奈的是我司程式碼瓶頸太多了,我一般是抓大放小,先從最嚴重的開始。
一些比較好找的點是,ORM的效能,比如odoo中filtered語句就比search語句執行的慢,而search語句中,若使用a.b.c
這種格式,那麼ORM在翻譯search語句至sql語句時,就會變成join語句,這樣執行的也慢。再比如,有些功能有更好的實現,比如說是優秀的第三方庫,那麼對原先的程式碼進行替換即可。
剩下的都是需要深入場景,深入程式碼邏輯中去判斷是否能夠優化。一般而言,如果一行程式碼執行時間過長,那麼就要進行思考,大體上,首先要想想是否需要這麼計算,再考慮怎麼優化。如果一行程式碼執行次數過多,那就要考慮是否有多次重複呼叫了。我在這次優化中,發現有一處呼叫了300多次,按照場景只需要60次即可,後來發現在程式碼邏輯中有一處是從上往下進行迴圈,在迴圈中呼叫了一個方法,這個方法又進行從下往上的遞迴,結果就往返執行了300多次。優化好之後,發現又有一個地方執行了3000多次,我真是百思不得其解啊,後來反覆查詢,才發現是有一個模型的方法中有一個自動觸發的方法,當有些屬性改變時就會進行呼叫。真可謂是一步一坑啊!
說了這麼多,其實我們也沒有涉及到很高階的技術,都是一些基礎。但是,從效能優化的工作中,也能夠看出一些問題,也就是所謂的根因:一是Model設計不合理,Model設計的好不好沒有標準,是有一些比較教條的規則,但更應該看的是Model的設計是不是非常符合實際的應用場景,我司的設計估計剛開始時還是符合的,但目前已經非常不匹配了。
二是程式碼質量不過關,我在上文所舉的那個例子,就是很好的證明,對於這點我只能說要看個人的自覺了,也沒有想到或是聽說過有很好的方法,code review這種東西在我司執行效果不佳。
三是極端測試不充分,否則也不會等到線上流量暴增之後,才發現這麼多效能問題。
四是效能未量化,當初在寫程式碼時,並沒有考慮到哪些地方對效能有要求,只是把功能簡單的實現而已。這就好比總分是100分,考了60分已經及格,但是總分突然提升到1000分時,60分就是個垃圾。雖然過早的優化是不對的,但是如果總是低要求的話,那就是挖坑不止,問題永遠都解決不完。
上面提到的都是通過技術解決。下面談談解決問題的思路,當然是個人見解。實際上遇到問題的時候,我們首要的考慮是,出現問題的場景是真需求還是偽需求,也就是說,問題並不需要都通過技術手段來解決,而且技術手段也不應該是首選。這個過程應該是一步步來,不斷地對各種取巧方法進行否定,直到無法可解,才去選擇技術來解決。
而當選取技術時,也並不是說直接硬上了,像是採用非同步、cache這種討巧的技術來解決問題其實是非常漂亮的。這次有個需要優化的地方執行了20s左右,原因是會對4000+個浮點數進行加運算,在實際當中,它是一個偽需求,我們通過一個tag來規避它,而通過一個定時任務來執行計算,而計算本身我也只是引入numpy的sum來替換python的內建sum。如果它真的是一個真需求的話,我才可能會去考慮多程序/執行緒,Map-Reduce,C程式碼等等其他技術。
這樣可能不太符合一個技術人員的定位,面對問題應該正面強上的啊,這樣才能證明自己啊……但我恰恰喜歡這種比較“取巧”,“暴力”的方法,而且認為這樣才足夠優雅。
最後說點其他的,關於死鎖。之前我是認為死鎖這種高大上的東西得非常大的資料才會出現,沒想到啊沒想到。歸根結底,一部分歸咎於ORM的實現,一部分則是程式碼實現太爛。如果執行夠快的話,行級鎖是很難觸發死鎖的。但是按照我司一個事務能執行30min+的尿性,不出死鎖才怪。目前我們把一些長事務給分拆,變成一個個小事務對資料庫進行commit,來規避死鎖的觸發。
總之,寫程式碼之前好好理清楚需求,好好設計架構,寫程式碼的時候要對人友好,要寫得優雅,寫完後要進行測試,要對各種可能出現的情況提前做好判斷,是否對效能有要求也要提前想好,並對實現進行驗證。
軟體工程,軟體工程,做工程一定要考慮成本,做工程一定有前有後有各種要求標準,軟體工程永遠都不是程式碼羅列。
相關推薦
最近處理的效能優化總結思考
按照常理,效能優化應該是屬於比較高階,處於專案中後期的工作了,但是如果實現不給力,在專案初期就可以遇到了。 很多人都嫌棄Python慢,個人認為他們之中90%都沒有資格這麼說,一方面,需要高效能的地方並不是每個專案都需要,另一方面,他們自己寫的程式碼爛的要死,才是罪魁禍首。
C程式碼效能優化總結
轉自:https://blog.csdn.net/chenyq991/article/details/79047741 1、優化程式碼框架 個人覺得程式碼架構對效能的影響至關重要,就好骨架之於人,所以我把這個放在第一點。舉個簡單的例子: 優化前: void main() { whi
TOMCAT7併發效能優化總結
最近由於工作需要看了很多tomcat效能優化的資料,在此記錄總結一下,以備日後之需。 總結起來其實有三點: 一、tomcat啟動JVM引數調優 具體做法為在catalina.bat前面加上JAVA_OPTS引數設定 set JAVA_OPTS= -server #以伺服
【HBase調優】Hbase萬億級儲存效能優化總結
背景:HBase主叢集在生產環境已穩定執行有1年半時間,最大的單表region數已達7200多個,每天新增入庫量就有百億條,對HBase的認識經歷了懵懂到熟的過程。為了應對業務資料的壓力,HBase入庫也由最初的單機多執行緒升級為有容災機制的分散式入庫,為及早發現叢集中的問題,還開發了一套對HBas
SQL 效能優化 總結
SQL 效能優化 總結 (1)選擇最有效率的表名順序(只在基於規則的優化器中有效): ORACLE的解析器按照從右到左的順序處理FROM子句中的表名,FROM子句中寫在最後的表(基礎表 driving table)
Unity3D效能優化總結
轉自https://www.cnblogs.com/quansir/p/6370796.html 一、程式方面 01、務必刪除指令碼中為空或不需要的預設方法; 02、只在一個指令碼中使用OnGUI方法; 03、避免在OnGUI中對變數、方法進行更新、賦值,輸出變數建
MySQL效能優化總結___本文乃《MySQL效能調優與架構設計》讀書筆記!
一、MySQL的主要適用場景 1、Web網站系統 2、日誌記錄系統 3、資料倉庫系統 4、嵌入式系統 二、MySQL架構圖: 三、MySQL儲存引擎概述 1)MyISAM儲存引擎 MyISAM儲存引擎的表在資料庫中,每一個表
35 個 Java 程式碼效能優化總結(一)
前言 程式碼優化,一個很重要的課題。可能有些人覺得沒用,一些細小的地方有什麼好修改的,改與不改對於程式碼的執行效率有什麼影響呢?這個問題我是這麼考慮的,就像大海里面的鯨魚一樣,它吃一條小蝦米有用嗎?沒用,但是,吃的小蝦米一多之後,鯨魚就被餵飽了。程式碼優化也是一樣,如果專案著眼於儘快無BUG
效能優化的思考
問:效能優化從哪些方面著手: 答: a). 平臺相關的方面:瞭解底層或者系統的原理,更合理的使用API; b). 程式碼邏輯演算法方面:合理的寫程式碼,做到優化程式碼結構,合理設計演算法,避免資源的浪費; c). 併發方面: i、響應的及時性: ① 可以合理使
35 個 Java 程式碼效能優化總結
前言 程式碼優化,一個很重要的課題。可能有些人覺得沒用,一些細小的地方有什麼好修改的,改與不改對於程式碼的執行效率有什麼影響呢?這個問題我是這麼考慮的,就像大海里面的鯨魚一樣,它吃一條小蝦米有用嗎?沒用,但是,吃的小蝦米一多之後,鯨魚就被餵飽了。程式碼優化也是
Hbase效能優化總結
本文主要是從HBase應用程式設計與開發的角度,總結幾種常用的效能優化方法。 Auto Flash 通過呼叫HTable.setAutoFlushTo(false)方法可以將HTable寫客戶端自動flush關閉,這樣可以批量寫入資料到HBase,而不是有一條put就執行
DPDK中的memcpy效能優化及思考
記憶體拷貝(memcpy)這個操作看似簡單,但長期以來存在很多關於其優化的討論,各種程式語言庫也都有對應實現,而對於memcpy效能評估測試的討論就更多了。 那麼如下的memcpy實現到底有什麼問題? void * simple_memcpy(void *ds
35個java程式碼效能優化總結
前言 程式碼優化,一個很重要的課題。可能有些人覺得沒用,一些細小的地方有什麼好修改的,改與不改對於程式碼的執行效率有什麼影響呢?這個問題我是這麼考慮 的,就像大海里面的鯨魚一樣,它吃一條小蝦米有用嗎?沒用,但是,吃的小蝦米一多之後,鯨魚就被餵飽了。程式碼優化也是一樣,如
44個Java程式碼效能優化總結
程式碼優化的最重要的作用應該是:避免未知的錯誤。在程式碼上線執行的過程中,往往會出現很多我們意想不到的錯誤,因為線上環境和開發環境是非常不同的,錯誤定位到最後往往是一個非常小的原因。然而為了解決這個錯誤,我們需要先自驗證、再打包出待替換的class檔案、暫停業務並重啟,對
MySQL效能優化總結
一、MySQL的主要適用場景 1、Web網站系統 2、日誌記錄系統 3、資料倉庫系統 4、嵌入式系統 二、MySQL架構圖: 三、MySQL儲存引擎概述 1)MyISAM儲存引擎 MyISAM儲存引擎的表在資料庫中,每一個表都被存放為三個以表名命名
Java 程式碼效能優化總結
程式碼優化的目標是: 1、減小程式碼的體積 2、提高程式碼執行的效率 程式碼優化細節 1、儘量指定類、方法的final修飾符 帶 有final修飾符的類是不可派生的。在Java核心API中,有許多應用final的例子,例如java.lang.String,整個類
35 個 Java 程式碼效能優化總結(複製於碼農網)
前言 程式碼優化,一個很重要的課題。可能有些人覺得沒用,一些細小的地方有什麼好修改的,改與不改對於程式碼的執行效率有什麼影響呢?這個問題我是這麼考慮的,就像大海里面的鯨魚一樣,它吃一條小蝦米有用嗎?沒用,但是,吃的小蝦米一多之後,鯨魚就被餵飽了。程式碼優化也是一樣,如果專案著眼於儘快無BUG
React效能優化總結
from:http://www.tuicool.com/articles/VNFZBbj 初學者對React可能滿懷期待,覺得React可能完爆其它一切框架,甚至不切實際地認為React可能連原生的渲染都能完爆——對框架的狂熱確實會出現這樣的不切實際的期待。讓我們來看看Re
ElasticSearch學習總結(七):效能優化總結
本文主要總結Elasticsearch效能優化方面的相關內容 1. 概述 效能優化是個涉及面非常廣的問題,不同的環境,不同的業務場景可能會存在不同的優化方案,本文只對一些相關的知識點做簡單的總結,具體方案可以根據場景自行嘗試。 1.1 效能測試 如果需要做效能調優,效能基準測
Java 程式碼效能優化總結(過來人經驗)
Java 程式碼效能優化總結(過來人經驗) 程式設計師界的彭于晏 2018-10-10 18:11:54 代 碼優化,一個很重要的課題。可能有些人覺得沒用,一些細小的地方有什麼好修改的,改與不改對於程式碼的執行效率有什麼影響呢?這個問題我是這麼考慮的,就像 大海里面的鯨魚一樣,它吃