天天看點

Python流程控制常用工具詳解

在我們的工作中,我們使用ddagent ver。5作為收集工具,收集和報告托管伺服器的性能名額,并對ddagent進行一定程度的定制。經過多次功能疊代,發現一批線上運作時間長的托管伺服器占用了太多記憶體。分析問題機器上程序樹中每個節點的占用情況,可以看出ddagent集合程序的記憶體占用仍然很高。

我們将學習最基本的流程控制工具,比如

if 條件判斷for 循環while 循環

作為保證業務系統穩定運作的監控元件,存在記憶體洩漏,這自然是非常嚴重的,是以我們開始了我們的“故障排除之旅”。

if-elif-else 判斷

Python流程控制常用工具詳解

分析

有很多工具可以分析和導出Python程式的記憶體狀态。在這裡,我們使用pyrasite,它可以附加到正在運作的Python程式,生成記憶體快照,并檢查目前哪些對象類型占用了多少記憶體,并從大到小排序。

使用指令非常簡單: pyrasite-memory-viewer <PID ,同時會生成一份快照檔案: /tmp/pyrasite-<PID -objects.json。

由于無法提供真實的生産資料,下面提到的所有資料都來自問題版本在測試環境中運作12小時後的采樣。

在pyrasite提供的Cui視圖中,我們可以清楚地看到字典類型的對象執行個體占用的記憶體最多,達到3.4mb,有6621個執行個體:

Python流程控制常用工具詳解

while 循環

While循環也是一種常見的循環方式。這種循環通常以循環體類或條件方式結束。它不可能無限期地進行下去。

Python流程控制常用工具詳解

對于洩漏情況,我們有以下事實和猜測:

一個或多個位置持續建立空字典對象,并且無法回收它們,進而導緻記憶體洩漏記憶體洩漏量随時間而增加。在索引收集業務中,洩漏很可能是在每個收集過程中引起的,并在間隔期之後重複觸發我們看不到目前依賴的ddagent版本存在尚未關閉的相關問題,這可能是在我們的定制過程中引入的錯誤

[
 [
 [".../embedded/lib/python2.7/threading.py",774,"__bootstrap","self.__bootstrap_inner()"],
 [".../embedded/lib/python2.7/threading.py",801,"__bootstrap_inner","self.run()"],
 [".../modules/monitor/bot/schedule.py",51,"run","task.run()"],
 [".../modules/monitor/bot/task.py",50,"run","super(RepeatTask, self).run()"],
 [".../modules/monitor/bot/task.py",18,"run","self.check()"],
 [".../modules/monitor/checks/collector.py",223,"wrapper","_check.run()"],
 [".../modules/monitor/checks/__init__.py",630,"run","self._roll_up_instance_metadata()"],
 [".../modules/monitor/checks/__init__.py",498,"_roll_up_instance_metadata","dict((k, v) for (k, v) in self._instance_metadata))"],
 [".../modules/monitor/tracer.py",33,"__init__","self.trace_info = traceback.extract_stack()"]
 ],
 [
 [".../embedded/lib/python2.7/threading.py",774,"__bootstrap","self.__bootstrap_inner()"],
 [".../embedded/lib/python2.7/threading.py",801,"__bootstrap_inner","self.run()"],
 [".../modules/monitor/bot/schedule.py",51,"run","task.run()"],
 [".../modules/monitor/bot/task.py",50,"run","super(RepeatTask, self).run()"],
 [".../modules/monitor/bot/task.py",18,"run","self.check()"],
 [".../modules/monitor/checks/collector.py",223,"wrapper","_check.run()"],
 [".../modules/monitor/checks/__init__.py",630,"run","self._roll_up_instance_metadata()"],
 [".../modules/monitor/checks/__init__.py",498,"_roll_up_instance_metadata","dict((k, v) for (k, v) in self._instance_metadata))"],
 [".../modules/monitor/tracer.py",33,"__init__","self.trace_info = traceback.extract_stack()"]
 ],
 [
 [".../embedded/lib/python2.7/threading.py",774,"__bootstrap","self.__bootstrap_inner()"],
 [".../embedded/lib/python2.7/threading.py",801,"__bootstrap_inner","self.run()"],
 [".../modules/monitor/bot/schedule.py",51,"run","task.run()"],
 [".../modules/monitor/bot/task.py",50,"run","super(RepeatTask, self).run()"],
 [".../modules/monitor/bot/task.py",18,"run","self.check()"],
 [".../modules/monitor/checks/collector.py",223,"wrapper","_check.run()"],
 [".../modules/monitor/checks/__init__.py",630,"run","self._roll_up_instance_metadata()"],
 [".../modules/monitor/checks/__init__.py",498,"_roll_up_instance_metadata","dict((k, v) for (k, v) in self._instance_metadata))"],
 [".../modules/monitor/tracer.py",33,"__init__","self.trace_info = traceback.extract_stack()"]
 ],
...           

複制

重播

我們不提“做好設計審查和規範審查”、“加強試驗階段品質檢驗工作”等“老生常談”,也值得我們反思。

要徹底防止和控制記憶體洩漏幾乎是不可能的,像rust這樣的安全程式設計語言也不能保證程式不會洩漏記憶體。

許多引發記憶體不安全的行為,如數組通路越界、通路釋放後的記憶體等,都可以通過制定更嚴格的程式設計模型(如rust提出的所有權+生命周期規則)甚至資料競争問題來避免。

然而,觸發記憶體洩漏的行為,如競争條件,需要開發人員将開發元件和業務規則結合起來。設想一個需要手動觸發重新整理的資料隊列。結果,我們在推送資料時忘記調用它。這種記憶體洩漏無法通過任何正常檢查規則來識别。

關鍵字函數是為了更形象地說明傳入參數的位置和具體用法。如果一個函數有四個或五個參數,而且一次傳入的參數太多,那麼很難讓人眼花缭亂。如果key=value用于傳入。

總結

通過本節的學習,我們了解了通過if else在不同條件下控制代碼流和執行不同代碼。for/while和如何定義函數有兩種不同的循環方法,包括函數的傳回值和參數傳遞方法、position參數傳遞和向函數傳遞參數時的key=value參數傳遞。

以上就是本文的全部内容,希望對大家的學習有所幫助。