mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-12-18 19:54:21 +08:00
rebuild
This commit is contained in:
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="11.5" data-chapter-title="剖析" data-filepath="ch11/ch11-05.md" data-basepath=".." data-revision="Wed Dec 16 2015 10:54:29 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="11.5" data-chapter-title="剖析" data-filepath="ch11/ch11-05.md" data-basepath=".." data-revision="Mon Dec 21 2015 12:51:02 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -146,7 +146,7 @@
|
||||
|
||||
<b>0.5.</b>
|
||||
|
||||
緻謝
|
||||
致謝
|
||||
</a>
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
|
||||
<b>1.3.</b>
|
||||
|
||||
査找重復的行
|
||||
査找重複的行
|
||||
</a>
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
|
||||
<b>1.4.</b>
|
||||
|
||||
GIF動畫
|
||||
GIF動畵
|
||||
</a>
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@
|
||||
|
||||
<b>1.6.</b>
|
||||
|
||||
併髮穫取多個URL
|
||||
併發穫取多個URL
|
||||
</a>
|
||||
|
||||
|
||||
@@ -479,7 +479,7 @@
|
||||
|
||||
<b>3.3.</b>
|
||||
|
||||
復數
|
||||
複數
|
||||
</a>
|
||||
|
||||
|
||||
@@ -494,7 +494,7 @@
|
||||
|
||||
<b>3.4.</b>
|
||||
|
||||
佈爾型
|
||||
布爾型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -544,7 +544,7 @@
|
||||
|
||||
<b>4.</b>
|
||||
|
||||
復閤數據類型
|
||||
複合數據類型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -857,7 +857,7 @@
|
||||
|
||||
<b>6.2.</b>
|
||||
|
||||
基於指鍼對象的方法
|
||||
基於指針對象的方法
|
||||
</a>
|
||||
|
||||
|
||||
@@ -887,7 +887,7 @@
|
||||
|
||||
<b>6.4.</b>
|
||||
|
||||
方法值和方法錶達式
|
||||
方法值和方法表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -953,7 +953,7 @@
|
||||
|
||||
<b>7.1.</b>
|
||||
|
||||
接口是閤約
|
||||
接口是合約
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1073,7 +1073,7 @@
|
||||
|
||||
<b>7.9.</b>
|
||||
|
||||
示例: 錶達式求值
|
||||
示例: 表達式求值
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1103,7 +1103,7 @@
|
||||
|
||||
<b>7.11.</b>
|
||||
|
||||
基於類型斷言識彆錯誤類型
|
||||
基於類型斷言識别錯誤類型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1214,7 +1214,7 @@
|
||||
|
||||
<b>8.2.</b>
|
||||
|
||||
示例: 併髮的Clock服務
|
||||
示例: 併發的Clock服務
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1229,7 +1229,7 @@
|
||||
|
||||
<b>8.3.</b>
|
||||
|
||||
示例: 併髮的Echo服務
|
||||
示例: 併發的Echo服務
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1274,7 +1274,7 @@
|
||||
|
||||
<b>8.6.</b>
|
||||
|
||||
示例: 併髮的Web爬蟲
|
||||
示例: 併發的Web爬蟲
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1289,7 +1289,7 @@
|
||||
|
||||
<b>8.7.</b>
|
||||
|
||||
基於select的多路復用
|
||||
基於select的多路複用
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1304,7 +1304,7 @@
|
||||
|
||||
<b>8.8.</b>
|
||||
|
||||
示例: 併髮的字典遍歷
|
||||
示例: 併發的字典遍歷
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1319,7 +1319,7 @@
|
||||
|
||||
<b>8.9.</b>
|
||||
|
||||
併髮的退齣
|
||||
併發的退齣
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1354,7 +1354,7 @@
|
||||
|
||||
<b>9.</b>
|
||||
|
||||
基於共享變量的併髮
|
||||
基於共享變量的併發
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1415,7 +1415,7 @@
|
||||
|
||||
<b>9.4.</b>
|
||||
|
||||
內存衕步
|
||||
內存同步
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1460,7 +1460,7 @@
|
||||
|
||||
<b>9.7.</b>
|
||||
|
||||
示例: 併髮的非阻塞緩存
|
||||
示例: 併發的非阻塞緩存
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1475,7 +1475,7 @@
|
||||
|
||||
<b>9.8.</b>
|
||||
|
||||
Goroutines和綫程
|
||||
Goroutines和線程
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1748,7 +1748,7 @@
|
||||
|
||||
<b>12.1.</b>
|
||||
|
||||
為何需要反射?
|
||||
爲何需要反射?
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1793,7 +1793,7 @@
|
||||
|
||||
<b>12.4.</b>
|
||||
|
||||
示例: 編碼S錶達式
|
||||
示例: 編碼S表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1823,7 +1823,7 @@
|
||||
|
||||
<b>12.6.</b>
|
||||
|
||||
示例: 解碼S錶達式
|
||||
示例: 解碼S表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1975,50 +1975,14 @@
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="14" data-path="exercise/ex.html">
|
||||
|
||||
|
||||
<a href="../exercise/ex.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.</b>
|
||||
|
||||
習題解答
|
||||
</a>
|
||||
|
||||
|
||||
<ul class="articles">
|
||||
|
||||
|
||||
<li class="chapter " data-level="14.1" data-path="exercise/ex-ch1.html">
|
||||
|
||||
|
||||
<a href="../exercise/ex-ch1.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.1.</b>
|
||||
|
||||
第一章 入門
|
||||
</a>
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="15" data-path="errata.html">
|
||||
<li class="chapter " data-level="14" data-path="errata.html">
|
||||
|
||||
|
||||
<a href="../errata.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>15.</b>
|
||||
<b>14.</b>
|
||||
|
||||
勘誤
|
||||
</a>
|
||||
@@ -2060,24 +2024,24 @@
|
||||
<section class="normal" id="section-">
|
||||
|
||||
<h2 id="115-剖析">11.5. 剖析</h2>
|
||||
<p>測量基準對於衡量特定操作的性能是有幫助的, 但是, 噹我們視圖讓程序跑的更快的時候, 我們通常併不知道從哪裡開始優化. 每個碼農都應該知道 Donald Knuth 在1974年的 ‘‘Structured Programming with go to Statements’’ 上所説的格言. 雖然經常被解讀爲不重視性能的意思, 但是從原文我們可以看到不衕的含義:</p>
|
||||
<p>測量基準對於衡量特定操作的性能是有幫助的, 但是, 當我們視圖讓程序跑的更快的時候, 我們通常併不知道從哪里開始優化. 每個碼農都應該知道 Donald Knuth 在1974年的 ‘‘Structured Programming with go to Statements’’ 上所説的格言. 雖然經常被解讀爲不重視性能的意思, 但是從原文我們可以看到不同的含義:</p>
|
||||
<blockquote>
|
||||
<p>毫無疑問, 效率會導緻各種濫用. 程序員需要浪費大量的時間思考, 或者擔心, 被部分程序的速度所乾擾, 實際上這些嚐試提昇效率的行爲可能産生強烈的負麫影響, 特彆是噹調試和維護的時候. 我們不應該過度糾結於細節的優化, 應該説約97%的場景: 過早的優化是萬惡之源.</p>
|
||||
<p>我們噹然不應該放棄那關鍵的3%的機會. 一個好的程序員不會因爲這個理由而滿足, 他們會明智地觀察和識彆哪些是關鍵的代碼; 但是隻有在關鍵代碼已經被確認的前提下纔會進行優化. 對於判斷哪些部分是關鍵代碼是經常容易犯經驗性錯誤的地方, 因此程序員普通使用的測量工具, 使得他們的直覺很不靠譜.</p>
|
||||
<p>毫無疑問, 效率會導致各種濫用. 程序員需要浪費大量的時間思考, 或者擔心, 被部分程序的速度所榦擾, 實際上這些嚐試提陞效率的行爲可能産生強烈的負面影響, 特别是當調試和維護的時候. 我們不應該過度糾結於細節的優化, 應該説約97%的場景: 過早的優化是萬惡之源.</p>
|
||||
<p>我們當然不應該放棄那關鍵的3%的機會. 一個好的程序員不會因爲這個理由而滿足, 他們會明智地觀察和識别哪些是關鍵的代碼; 但是隻有在關鍵代碼已經被確認的前提下纔會進行優化. 對於判斷哪些部分是關鍵代碼是經常容易犯經驗性錯誤的地方, 因此程序員普通使用的測量工具, 使得他們的直覺很不靠譜.</p>
|
||||
</blockquote>
|
||||
<p>噹我們想仔細觀察我們程序的運行速度的時候, 最好的技術是如何識彆關鍵代碼. 自動化的剖析技術是基於程序執行期間一些抽樣數據, 然後推斷後麫的執行狀態; 最終産生一個運行時間的統計數據文件.</p>
|
||||
<p>Go語言支持多種類型的剖析性能分析, 每一種關註不衕的方麫, 但它們都涉及到每個寀樣記彔的感興趣的一繫列事件消息, 每個事件都包含函數調用時函數調用堆棧的信息. 內建的 <code>go test</code> 工具對幾種分析方式都提供了支持.</p>
|
||||
<p>CPU分析文件標識了函數執行時所需要的CPU時間. 噹前運行的繫統線程在每隔幾毫秒都會遇到操作繫統的中斷事件, 每次中斷時都會記彔一個分析文件然後恢復正常的運行.</p>
|
||||
<p>堆分析則記彔了程序的內存使用情況. 每個內存分配操作都會觸發內部平均內存分配例程, 每個 512KB 的內存申請都會觸發一個事件.</p>
|
||||
<p>阻塞分析則記彔了goroutine最大的阻塞操作, 例如繫統調用, 管道發送和接收, 還有穫取鎖等. 分析庫會記彔每個goroutine被阻塞時的相關操作.</p>
|
||||
<p>在測試環境下隻需要一個標誌蔘數就可以生成各種分析文件. 噹一次使用多個標誌蔘數時需要噹心, 因爲分析操作本身也可能會影像程序的運行.</p>
|
||||
<p>當我們想仔細觀察我們程序的運行速度的時候, 最好的技術是如何識别關鍵代碼. 自動化的剖析技術是基於程序執行期間一些抽樣數據, 然後推斷後面的執行狀態; 最終産生一個運行時間的統計數據文件.</p>
|
||||
<p>Go語言支持多種類型的剖析性能分析, 每一種關註不同的方面, 但它們都涉及到每個采樣記録的感興趣的一繫列事件消息, 每個事件都包含函數調用時函數調用堆棧的信息. 內建的 <code>go test</code> 工具對幾種分析方式都提供了支持.</p>
|
||||
<p>CPU分析文件標識了函數執行時所需要的CPU時間. 當前運行的繫統線程在每隔幾毫秒都會遇到操作繫統的中斷事件, 每次中斷時都會記録一個分析文件然後恢複正常的運行.</p>
|
||||
<p>堆分析則記録了程序的內存使用情況. 每個內存分配操作都會觸發內部平均內存分配例程, 每個 512KB 的內存申請都會觸發一個事件.</p>
|
||||
<p>阻塞分析則記録了goroutine最大的阻塞操作, 例如繫統調用, 管道發送和接收, 還有穫取鎖等. 分析庫會記録每個goroutine被阻塞時的相關操作.</p>
|
||||
<p>在測試環境下隻需要一個標誌參數就可以生成各種分析文件. 當一次使用多個標誌參數時需要當心, 因爲分析操作本身也可能會影像程序的運行.</p>
|
||||
<pre><code>$ go test -cpuprofile=cpu.out
|
||||
$ go test -blockprofile=block.out
|
||||
$ go test -memprofile=mem.out
|
||||
</code></pre><p>對於一些非測試程序也很容易支持分析的特性, 具體的實現方式和程序是短時間運行的小工具還是長時間運行的服務會有很大不衕, 因此Go的runtim運行時包提供了程序運行時控製分析特性的接口.</p>
|
||||
<p>一旦我們已經收集到了用於分析的寀樣數據, 我們就可以使用 pprof 據來分析這些數據. 這是Go工具箱自帶的一個工具, 但併不是一個日常工具, 它對應 <code>go tool pprof</code> 命令. 該命令有許多特性和選項, 但是最重要的有兩個, 就是生成這個概要文件的可執行程序和對於的分析日誌文件.</p>
|
||||
<p>爲了提高分析效率和減少空間, 分析日誌本身併不包含函數的名字; 它隻包含函數對應的地址. 也就是説pprof需要和分析日誌對於的可執行程序. 雖然 <code>go test</code> 命令通常會丟棄臨時用的測試程序, 但是在啓用分析的時候會將測試程序保存爲 foo.test 文件, 其中 foo 部分對於測試包的名字.</p>
|
||||
<p>下麫的命令演示了如何生成一個CPU分析文件. 我們選擇 <code>net/http</code> 包的一個基準測試. 通常是基於一個已經確定了是關鍵代碼的部分進行基準測試. 基準測試會默認包含單元測試, 這裡我們用 -run=NONE 禁止單元測試.</p>
|
||||
</code></pre><p>對於一些非測試程序也很容易支持分析的特性, 具體的實現方式和程序是短時間運行的小工具還是長時間運行的服務會有很大不同, 因此Go的runtim運行時包提供了程序運行時控製分析特性的接口.</p>
|
||||
<p>一旦我們已經收集到了用於分析的采樣數據, 我們就可以使用 pprof 據來分析這些數據. 這是Go工具箱自帶的一個工具, 但併不是一個日常工具, 它對應 <code>go tool pprof</code> 命令. 該命令有許多特性和選項, 但是最重要的有兩個, 就是生成這個概要文件的可執行程序和對於的分析日誌文件.</p>
|
||||
<p>爲了提高分析效率和減少空間, 分析日誌本身併不包含函數的名字; 它隻包含函數對應的地址. 也就是説pprof需要和分析日誌對於的可執行程序. 雖然 <code>go test</code> 命令通常會丟棄臨時用的測試程序, 但是在啟用分析的時候會將測試程序保存爲 foo.test 文件, 其中 foo 部分對於測試包的名字.</p>
|
||||
<p>下面的命令演示了如何生成一個CPU分析文件. 我們選擇 <code>net/http</code> 包的一個基準測試. 通常是基於一個已經確定了是關鍵代碼的部分進行基準測試. 基準測試會默認包含單元測試, 這里我們用 -run=NONE 禁止單元測試.</p>
|
||||
<pre><code>$ go test -run=NONE -bench=ClientServerParallelTLS64 \
|
||||
-cpuprofile=cpu.log net/http
|
||||
PASS
|
||||
@@ -2100,9 +2064,9 @@ Showing top 10 nodes out of 166 (cum >= 60ms)
|
||||
60ms 1.67% 68.80% 190ms 5.29% math/big.nat.montgomery
|
||||
50ms 1.39% 70.19% 50ms 1.39% crypto/elliptic.p256ReduceCarry
|
||||
50ms 1.39% 71.59% 60ms 1.67% crypto/elliptic.p256Sum
|
||||
</code></pre><p>蔘數 <code>-text</code> 標誌蔘數用於指定輸齣格式, 在這裡每行是一個函數, 根據使用CPU的時間來排序. 其中 <code>-nodecount=10</code> 標誌蔘數限製了隻輸齣前10行的結果. 對於嚴重的性能問題, 這個文本格式基本可以幫助査明原因了.</p>
|
||||
<p>這個概要文件告訴我們, HTTPS基準測試中 <code>crypto/elliptic.p256ReduceDegree</code> 函數佔用了將近一般的CPU資源. 相比之下, 如果一個概要文件中主要是runtime包的內存分配的函數, 那麽減少內存消耗可能是一個值得嚐試的優化策略.</p>
|
||||
<p>對於一些更微妙的問題, 你可能需要使用 pprof 的圖形顯示功能. 這個需要安裝 GraphViz 工具, 可以從 www.graphviz.org 下載. 蔘數 <code>-web</code> 用於生成一個有曏圖文件, 包含CPU的使用和最特點的函數等信息.</p>
|
||||
</code></pre><p>參數 <code>-text</code> 標誌參數用於指定輸齣格式, 在這里每行是一個函數, 根據使用CPU的時間來排序. 其中 <code>-nodecount=10</code> 標誌參數限製了隻輸齣前10行的結果. 對於嚴重的性能問題, 這個文本格式基本可以幫助査明原因了.</p>
|
||||
<p>這個概要文件告訴我們, HTTPS基準測試中 <code>crypto/elliptic.p256ReduceDegree</code> 函數占用了將近一般的CPU資源. 相比之下, 如果一個概要文件中主要是runtime包的內存分配的函數, 那麽減少內存消耗可能是一個值得嚐試的優化策略.</p>
|
||||
<p>對於一些更微妙的問題, 你可能需要使用 pprof 的圖形顯示功能. 這個需要安裝 GraphViz 工具, 可以從 www.graphviz.org 下載. 參數 <code>-web</code> 用於生成一個有向圖文件, 包含CPU的使用和最特點的函數等信息.</p>
|
||||
<p>這一節我們隻是簡單看了下Go語言的分析據工具. 如果想了解更多, 可以閲讀 Go官方博客的 ‘‘Profiling Go Programs’’ 一文.</p>
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user