官术网_书友最值得收藏!

1.4 如何成為高性能程序員

長期看,要成功地確保項目的高性能,編寫出高性能代碼只是一個方面。相比于加速和復雜的解決方案,整個團隊的效率要重要得多。為確保團隊效率,有幾個因素至關重要:良好的結構和文檔、易于調試以及遵循相同的標準。

假設你開發了一個原型,它雖未經詳盡測試,也沒有經過團隊審核,但看起來“足夠好”,因此被推送到了生產環境中。因為它從來沒有以結構化的方式編寫,所以它缺乏測試且沒有文檔化。突然之間,這增添了需要他人來支持的代碼,而管理人員通常無法評估團隊將為此付出什么樣的代價。

這種解決方案難以維護,往往不受歡迎(沒人去修改其結構,沒人去添加可幫助重構的測試,更沒有其他人愿意接手),因此確保其正常運行的工作始終落在最初接手的那個開發人員身上。這可能在緊急的情況下導致可怕的瓶頸,還可能帶來重大風險:如果這位開發人員離開了,結果將如何呢?

通常,管理團隊對難以維護的代碼帶來的慣性認識不足時,就會出現這種開發風格。事實證明,從長遠看,測試和文檔有助于保持團隊的高效率,還有助于說服管理層分配用于整理原型代碼的時間。

在研究環境中驗證各種想法和數據集時,經常會在未遵循良好編碼實踐的情況下創建大量Jupyter Notebook。這背后的理念是以后再正確地編寫,但實際上根本沒有以后。因此最終的成果是一系列可運行的代碼,但沒有對代碼進行重現、測試和確保它們可信任的基礎設施。同樣,這種成果帶來的風險很高,而可信度又很低。

為避免上述情況發生,可采用以下通用方法。

確保可行:先創建一個足夠好的解決方案。創建用后即棄的原型解決方案合乎情理,這讓你能夠在第二個版本中采用更佳的結構。編碼前做些規劃工作總是明智的選擇,不然你肯定會后悔“整個下午都在編碼,而沒有花1小時來思考”。在有些領域,這被稱為“三思而后行”。

確保正確:接下來,添加強大的測試套件,并輔以良好的文檔和清晰的重現說明,讓其他團隊成員能夠快速接手項目。

提高速度:最后,將重點放在剖析和編譯或并行化上,使用既有測試套件核實改進后的解決方案仍然可以按預期工作。

1.4.1 最佳實踐

有一些東西是必不可少的,這包括文檔、良好的結構和測試,它們至關重要。

項目級文檔有助于確保結構始終清晰,還可在未來給你和同事提供幫助;如果你省略這部分,沒有人(包括你自己)會感謝你。一種合理的做法是,先將這種文檔作為一個頂級README文件,以后必要時再將其擴展為一個docs/文件夾。

闡述項目的目的、各個文件夾包含的內容、數據來自何方、哪些文件至關重要以及如何運行項目(包括測試)。

Micha推薦同時使用Docker,這樣將有一個頂級Dockerfile,它準確地指出了要成功地運行項目,需要哪些操作系統庫,還讓你能夠輕松地在其他計算機中運行項目以及將其部署到云環境中。

添加一個包含單元測試的tests/文件夾。我們喜歡使用測試框架pytest,因為它是建立在Python內置模塊unittest的基礎之上的。先編寫兩三個測試,然后慢慢添加,再逐步采用覆蓋工具,因為它會指出測試覆蓋了多少行代碼,有助于避免令人討厭的意外情況。

如果繼承了缺乏測試的遺留代碼,那么先給它添加測試將帶來極高的回報。另外,編寫一些集成測試,對整個項目流程進行檢查,確認特定的數據輸入將生成特定輸出,這有助于你在以后修改代碼時保持理智。

每當遇到代碼出現問題時,都添加一個測試。在同一個地方跌倒兩次毫無意義。

在代碼中,給每個函數、類和模塊都編寫文檔字符串,這大有裨益。你的目標是提供有用的描述,指出函數實現了什么,并在可能的情況下通過簡短的示例指出函數的預期輸出。要獲得靈感,請看看numpy和scikit-learn中的文檔字符串。

每當你發現代碼塊太長(如函數超過一屏)時,一定要通過重構來縮短它們。代碼塊越短,測試和支持起來就越輕松。

提示:編寫測試時,請考慮遵循測試驅動的開發方法。在準確地知道需要開發什么且有現成的可測試示例的情況下,這種方法的效率極高。

你編寫并運行測試,發現它們不能通過,再添加函數和最起碼的邏輯,讓測試得以通過。對所有的工作都進行測試后,就大功告成了。預先確定函數期望的輸入和輸出后,你將發現函數的邏輯實現起來非常容易。

如果你無法預先定義測試,那么一個自然而然的問題是,你真的明白相應的函數需要做什么嗎?如果不明白,又怎么可能正確而高效地編寫它呢?如果你采用的流程是創造性的,且對要研究的數據認識不太深刻,那么這種方法就不管用了。

務必進行源代碼版本控制,當你在不方便的時候需要重寫某些代碼時,一定會為自己進行版本控制感到慶幸。養成頻繁提交(每天乃至每10分鐘提交一次)以及每天推送到倉庫的習慣。

務必遵循編碼標準PEP8。錦上添花的做法是,對未提交的版本控制鉤子采用black(非常嚴格的代碼格式設置程序),使其根據標準修改代碼。同時,使用flake8對代碼進行檢查,以避免其他錯誤。

創建與操作系統隔離的環境可讓工作更輕松。作者Ian喜歡使用Anaconda,而Micha 喜歡與Docker配套的pipenv。這兩種方案都可行,比使用操作系統的全局Python環境要好得多。

別忘了自動化是你的朋友,減少手動工作就意味著降低了錯誤出現的概率。通過使用自動化的測試套件運行程序,將構建系統、持續集成的工作自動化,而通過自動化系統部署過程,可將易于出錯的煩瑣任務變成任何人都能夠運行和支持的標準流程。

最后,別忘了可讀性遠比抖機靈重要。在你和同事的維護工作中,簡短但復雜而難以理解的代碼片段將是攔路虎,讓人感到害怕,不敢去觸碰。因此,請讓函數更容易理解(哪怕這樣導致其代碼更長),并輔以有用的文檔,指出函數將返回什么,同時添加測試,用以核實函數像你期望的那樣工作。

1.4.2 對Notebook最佳實踐的思考

Jupyter Notebook雖然非常適合用于以視覺化方式交流,但會慣出用戶懶惰的毛病。如果你發現Notebook中有很長的函數,請務必將它們提取到Python模塊中,再添加相應的測試。

可考慮在IPython或QTConsole中編寫原型代碼,再將代碼行轉換為Notebook中的函數,然后將函數提取到模塊中并添加配套的測試。最后,如果封裝和數據隱藏會有所幫助,請考慮將代碼封裝在類中。

為檢查函數是否像你期望的那樣工作,Notebook中可能充斥著assert語句。在Notebook中,除非對函數進行重構,將其放到模塊中,否則無法輕松地測試代碼,而assert檢查是一種實現進一步驗證的簡單方式。除非將代碼提取到模塊中,并編寫合理的單元測試,否則它們是不可信的。

不提倡在代碼中使用assert語句來檢查數據。它是一種核實特定條件是否滿足的簡單方式,但并不符合Python的語言習慣。為讓代碼更容易理解,請檢查數據的狀態是否符合預期,并在不符合預期時引發合適的異常。一種常見的異常是ValueError,它在函數收到的值不符合預期時觸發。Bulwark庫是一個專注于Pandas的測試框架,可用于檢查數據是否滿足指定的約束條件。

你可能還需在Notebook末尾添加一些完整性檢查,這包括邏輯檢查以及指出結果符合預期的raise和print語句。當你半年后再來看這些代碼時,肯定會慶幸你以前所做的工作,讓你能夠輕松地確定它們是否能正確地工作。

使用Jupyter Notebook的一個麻煩是,難以將代碼與版本控制系統共享。nbdime是一套新工具,讓你能夠比較不同的Notebook。這是一款救命神器,讓你能夠與同事協同工作。

1.4.3 重新發現工作的樂趣

人生可能復雜難懂。從本書第1版推出到現在已過去了5年,在此期間,兩位作者的家人和朋友遭遇了很多變故,其中包括抑郁、癌癥、搬家、生意上的成功和失敗以及職業方向的轉變。這些外部變故不可避免地會影響工作和生活前景。

千萬別忘了不斷地尋找工作和生活中的樂趣。只要開始尋找,總能發現有趣的細節或要求。你可能會問,他們為何會做出那樣的決定,如果換成我,會做出什么不同的決定。這可能讓你醍醐灌頂,順利地開啟有關如何改變或改進的對話。

將值得慶賀的事情記錄下來。人們很容易深陷日常瑣事,將成績拋諸腦后;當你為跟上時代不斷向前奔跑時,就會忘記自己取得的巨大進步。

建議你用一個清單將值得慶賀的事項記錄下來,并注明是如何慶賀的。Ian就有一個這樣的清單,每當他去更新這個清單時都會又驚又喜:原來上一年竟然有如此多的好事,要不是更新清單,他早已將這些好事忘在腦后了。這個清單不僅包含工作成就,還有業余愛好和運動方面的好事,以及慶賀成就的情況。Micha的做法是,確保將個人生活放在第一位,并在遠離計算機的時候專注于非技術項目。不斷提高技能至關重要,但這并不意味著必然失去熱情!

編程有賴于好奇心,還有對深究技術細節的樂此不疲,在需要專注于性能時尤其如此。可惜當你失去熱情后,首先消失的就是這種好奇心,因此請花時間確保旅途愉快,將樂趣和好奇心保留下來。

主站蜘蛛池模板: 遂昌县| 乌审旗| 高青县| 襄樊市| 辽阳市| 夹江县| 健康| 岳阳市| 博乐市| 泰兴市| 漳浦县| 广安市| 镇沅| 巴楚县| 收藏| 同心县| 疏勒县| 武胜县| 文登市| 彩票| 侯马市| 富源县| 平和县| 安平县| 涪陵区| 信丰县| 香河县| 体育| 盱眙县| 中西区| 古田县| 镇巴县| 吴江市| 江城| 阳朔县| 宝清县| 汽车| 防城港市| 松阳县| 沅江市| 南投县|