這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
同時發布在獨立部落格。
以前一直以為,在Golang中,針對高並發的情況,採用多核處理一定效果最優,但是項目實踐證明事實不是這樣的。
在Sniper項目中(一個結合了ab和siege優點的http負載測試工具),原來一直設定cup使用數為系統cpu總數:
runtime.GOMAXPROCS(runtime.NumCPU())
在與ab的效能比較中一直有較大差距,GET請求區域網路的一個10k大小的檔案:
以下是ab的效能,並發100,總請求100k,執行時間16.082秒
Concurrency Level: 100
Time taken for tests: 16.082 seconds
Complete requests: 100000
Failed requests: 0
Write errors: 0
Total transferred: 1035500000 bytes
HTML transferred: 1024000000 bytes
Requests per second: 6218.04 [#/sec] (mean)
Time per request: 16.082 [ms] (mean)
Time per request: 0.161 [ms] (mean, across all concurrent requests)
Transfer rate: 62878.74 [Kbytes/sec] received
接下來採用sniper測試,設定runtime.GOMAXPROCS(runtime.NumCPU())
Transactions: 100000 hits
Availability: 100.00 %
Elapsed time: 20.82 secs
TotalTransfer: 0.00 MB
HTMLTransfer: 0.00 MB
Transaction rate: 4802.45 trans/sec
Throughput: 0.00 MB/sec
Successful: 100000 hits
Failed: 0 hits
TransactionTime: 0.00021 secs(mean)
ConnectionTime: 0.00010 secs(mean)
RequestTime: 0.00000 secs(mean)
ResponseTime: 0.00011 secs(mean)
可以看到測試同樣的伺服器,使用全部的cpu,sniper耗時20.82秒。
最後我再設定runtime.GOMAXPROCS(1)
Transactions: 100000 hits
Availability: 100.00 %
Elapsed time: 16.71 secs
TotalTransfer: 0.00 MB
HTMLTransfer: 0.00 MB
Transaction rate: 5985.03 trans/sec
Throughput: 0.00 MB/sec
Successful: 100000 hits
Failed: 0 hits
TransactionTime: 0.00017 secs(mean)
ConnectionTime: 0.00003 secs(mean)
RequestTime: 0.00000 secs(mean)
ResponseTime: 0.00014 secs(mean)
可以看到,sniper的執行時間降到16.71秒,降低了20%。
沒想到最佳化了這麼久的效能最後竟然通過這樣的辦法前進一大步!
出現這種情況原因在哪裡?
目前我也解釋不清楚,可能跟CPU的環境切換有關,詳細的原理需要再研究。有知道原理原因的請指教。
update:
一個可能的原因:在這裡看到
和所有其他並發架構裡的協程一樣,goroutine裡所謂“無鎖”的優點只在單線程下有效,如果$GOMAXPROCS > 1並且協程間需要通訊,Go運行庫會負責加鎖保護資料。sniper存在大量的協程間通訊,可能是鎖影響了效能。