成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

用 panic-recover 做錯(cuò)誤處理?會(huì)影響 Go 程序性能的

開發(fā) 前端
對(duì)于 Go 應(yīng)用來講,這種方式也是有一定的損耗。今天結(jié)合在網(wǎng)上看到的 The cost of Go’s panic and recover 和大家一起來看看。

Go 這一門編程語(yǔ)音的 if err != nil 錯(cuò)誤處理機(jī)制一直飽受爭(zhēng)議。既然爭(zhēng)議那么多,想必有很多人想出各種奇思妙計(jì),試圖解決這個(gè)問題。

其中一個(gè)辦法是使用 panic-recover 來替代 if err != nil 來做錯(cuò)誤處理機(jī)制。

對(duì)于 Go 應(yīng)用來講,這種方式也是有一定的損耗。今天結(jié)合在網(wǎng)上看到的 The cost of Go’s panic and recover 和大家一起來看看。

Effective Java 例子

原作者 @Julien Cretel 是在閱讀經(jīng)典作品《Effective Java》中學(xué)習(xí)時(shí),看到 Java 異常進(jìn)行控制流的示例:

try {
  int i = 0;
  while (true)
    range[i++].climb();
} catch (ArrayIndexOutOfBoundsException e) {
}

該程序的變量 i 最終會(huì)遞增到數(shù)組的長(zhǎng)度,此時(shí)如果試圖訪問索引 i 處的數(shù)組,就會(huì)引發(fā) ArrayIndexOutOfBoundsException 異常,該異常會(huì)被捕獲并立即忽略。

使用 panic/recover 做控制流

很多 Java、PHP 等其他很多編程語(yǔ)言轉(zhuǎn)過來的同學(xué),第一次接觸 Go 時(shí),會(huì)試圖像上述例子去尋找能做一定的 try-catch 錯(cuò)誤處理機(jī)制的例子。

而在 Go 這一門編程語(yǔ)言中,能做到的類似模式的只有 panic-recover 的機(jī)制,因此可能產(chǎn)生了一些濫用的情況。

下述是模擬 Java try-catch 示例粗略翻譯成 Go panic-recover 示例的演示,以此驗(yàn)證性能基準(zhǔn)的測(cè)試。

1、主程序:

package main

type Mountain struct {
 climbed bool
}

func (m *Mountain) Climb() {
 m.climbed = true
}

func main() {
 mountains := make([]Mountain, 8)
 ClimbAllPanicRecover(mountains)
}

func ClimbAllPanicRecover(mountains []Mountain) {
deferfunc() {
recover()
 }()
for i := 0; ; i++ {
  mountains[i].Climb()
 }
}

func ClimbAll(mountains []Mountain) {
for i := range mountains {
  mountains[i].Climb()
 }
}

2、基準(zhǔn)測(cè)試:

package main

import (
"fmt"
"testing"
)

var cases [][]Mountain

func init() {
for _, size := range []int{0, 1, 1e1, 1e2, 1e3, 1e4, 1e5} {
  s := make([]Mountain, size)
  cases = append(cases, s)
 }
}

func BenchmarkClimbAll(b *testing.B) {
 benchmark(b, "idiomatic", ClimbAll)
 benchmark(b, "panic-recover", ClimbAllPanicRecover)
}

func benchmark(b *testing.B, impl string, climbAll func([]Mountain)) {
for _, ns := range cases {
  f := func(b *testing.B) {
   b.ReportAllocs()
   for b.Loop() {
    climbAll(ns)
   }
  }
  desc := fmt.Sprintf("impl=%s/size=%d", impl, len(ns))
  b.Run(desc, f)
 }
}

測(cè)試結(jié)果

從測(cè)試結(jié)果可以得知,即使是在處理小規(guī)模輸入切片時(shí),ClimbAllPanicRecover 的性能也明顯劣于 ClimbAll 的實(shí)現(xiàn)。

如下測(cè)試報(bào)告:

?  demo1 benchstat -col '/impl@(idiomatic panic-recover)' results.txt
goos: darwin
goarch: arm64
pkg: example.com/greet
cpu: Apple M3 Pro
                        │  idiomatic   │             panic-recover              │
                        │    sec/op    │    sec/op     vs base                  │
ClimbAll/size=0-11        1.046n ± 32%   94.320n ± 0%  +8921.52% (p=0.000 n=10)
ClimbAll/size=1-11        1.612n ± 20%   94.400n ± 0%  +5754.26% (p=0.000 n=10)
ClimbAll/size=10-11       4.202n ±  6%   97.565n ± 0%  +2221.87% (p=0.000 n=10)
ClimbAll/size=100-11      26.69n ±  0%   120.20n ± 0%   +350.36% (p=0.000 n=10)
ClimbAll/size=1000-11     255.0n ±  0%    354.8n ± 2%    +39.14% (p=0.000 n=10)
ClimbAll/size=10000-11    2.479μ ±  0%    2.595μ ± 0%     +4.68% (p=0.000 n=10)
ClimbAll/size=100000-11   24.72μ ±  0%    24.87μ ± 0%     +0.61% (p=0.001 n=10)
geomean                   60.46n          422.2n        +598.25%

                        │  idiomatic  │        panic-recover         │
                        │    B/op     │    B/op     vs base          │
ClimbAll/size=0-11        0.00 ± 0%     24.00 ± 0%  ? (p=0.000 n=10)
ClimbAll/size=1-11        0.00 ± 0%     24.00 ± 0%  ? (p=0.000 n=10)
ClimbAll/size=10-11       0.00 ± 0%     24.00 ± 0%  ? (p=0.000 n=10)
ClimbAll/size=100-11      0.00 ± 0%     24.00 ± 0%  ? (p=0.000 n=10)
ClimbAll/size=1000-11     0.00 ± 0%     24.00 ± 0%  ? (p=0.000 n=10)
ClimbAll/size=10000-11    0.00 ± 0%     24.00 ± 0%  ? (p=0.000 n=10)
ClimbAll/size=100000-11   0.00 ± 0%     24.00 ± 0%  ? (p=0.000 n=10)
geomean                             1   24.00       ?
1 summaries must be >0 to compute geomean

                        │  idiomatic   │        panic-recover         │
                        │  allocs/op   │ allocs/op   vs base          │
ClimbAll/size=0-11        0.000 ± 0%     1.000 ± 0%  ? (p=0.000 n=10)
ClimbAll/size=1-11        0.000 ± 0%     1.000 ± 0%  ? (p=0.000 n=10)
ClimbAll/size=10-11       0.000 ± 0%     1.000 ± 0%  ? (p=0.000 n=10)
ClimbAll/size=100-11      0.000 ± 0%     1.000 ± 0%  ? (p=0.000 n=10)
ClimbAll/size=1000-11     0.000 ± 0%     1.000 ± 0%  ? (p=0.000 n=10)
ClimbAll/size=10000-11    0.000 ± 0%     1.000 ± 0%  ? (p=0.000 n=10)
ClimbAll/size=100000-11   0.000 ± 0%     1.000 ± 0%  ? (p=0.000 n=10)
geomean                              1   1.000       ?
1 summaries must be >0 to compute geomean

具體差異體現(xiàn)在:

  • 執(zhí)行效率差距:在小數(shù)據(jù)集場(chǎng)景下,panic/recover 的操作成本占據(jù)主導(dǎo)地位,導(dǎo)致 ClimbAllPanicRecover 運(yùn)行遲緩。在 64 位系統(tǒng)中,每次調(diào)用會(huì)產(chǎn)生 24 字節(jié)的堆內(nèi)存分配(推測(cè)源于運(yùn)行時(shí)觸發(fā)的 runtime.boundsError 邊界錯(cuò)誤)。
  • 內(nèi)存管理差異:標(biāo)準(zhǔn)實(shí)現(xiàn) ClimbAll 完全避免了內(nèi)存分配,因此不會(huì)對(duì)垃圾回收機(jī)制造成額外壓力。
  • 性能趨勢(shì)變化:隨著輸入切片長(zhǎng)度的增加,兩種實(shí)現(xiàn)的性能差異逐漸縮小。這是因?yàn)?panic-recover 的固定開銷被更大的計(jì)算量所稀釋,不再成為主要性能瓶頸。

為什么 Go 不支持 try-catch

Go 官方早在《Error Handling — Problem Overview[1]》提案早已明確提過,Go 官方在設(shè)計(jì)上會(huì)有意識(shí)地選擇使用顯式錯(cuò)誤結(jié)果和顯式錯(cuò)誤檢查。

結(jié)合《language: Go 2: error handling meta issue[2]》可得知,要拒絕 try-catch 關(guān)鍵字的主要原因是:

  • 會(huì)涉及到額外的流程控制,因?yàn)槭褂?try 的復(fù)雜表達(dá)式,會(huì)導(dǎo)致函數(shù)意外返回。
  • 在表達(dá)式層面上沒有流程控制結(jié)構(gòu),只有 panic 關(guān)鍵字,它不只是從一個(gè)函數(shù)返回。

說白了,就是設(shè)計(jì)理念不合,加之實(shí)現(xiàn)上也不大合理。在以往的多輪討論中早已被 Go 團(tuán)隊(duì)拒絕了。

反之 Go 團(tuán)隊(duì)倒是一遍遍在回答這個(gè)問題,已經(jīng)不大耐煩了,直接都整理了 issues 版的 FAQ 了。

圖片圖片

總結(jié)

對(duì)于 Go 這一門編程語(yǔ)言來講,if err != nil 是其提供的最基本的錯(cuò)誤處理機(jī)制。

雖然很多開發(fā)同學(xué)略感不適,但官方依然是建議在其基礎(chǔ)上做設(shè)計(jì)模式的設(shè)計(jì)和調(diào)整。這是較為推薦的。

在很多妙計(jì)中,也有像本文使用 panic-recover 的方式。但通過實(shí)際測(cè)試來講,是會(huì)明確影響性能的。

官方也明確過不推薦該類錯(cuò)誤處理機(jī)制的方式。

見仁見智了。

參考資料

[1] Error Handling — Problem Overview: https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md

[2] language: Go 2: error handling meta issue: https://github.com/golang/go/issues/40432

責(zé)任編輯:武曉燕 來源: 腦子進(jìn)煎魚了
相關(guān)推薦

2023-03-10 08:48:29

2020-12-17 06:25:05

Gopanic 模式

2025-03-31 00:29:44

2024-06-05 08:47:20

Go語(yǔ)言方式

2022-12-12 08:53:53

Go版本方式

2022-07-08 08:55:56

Go函數(shù)模型

2014-11-17 10:05:12

Go語(yǔ)言

2021-04-29 09:02:44

語(yǔ)言Go 處理

2025-06-09 01:15:00

2021-09-27 10:04:03

Go程序處理

2021-09-27 15:33:48

Go 開發(fā)技術(shù)

2023-10-09 07:14:42

panicGo語(yǔ)言

2024-02-28 08:54:57

switchGo錯(cuò)誤

2025-05-22 09:01:28

2025-02-24 09:30:15

2025-06-06 06:45:54

2021-09-13 07:53:31

Go錯(cuò)誤處理

2022-09-05 08:55:15

Go2提案語(yǔ)法

2022-05-26 08:53:47

Go函數(shù)代碼

2024-03-14 09:35:54

Go 錯(cuò)誤select代碼
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 久久i | 日本一区二区不卡视频 | 色视频网站| 亚洲一二三区在线观看 | 在线播放一区 | 久久久精品一区二区三区 | 国产精品美女久久久久久免费 | 日韩欧美在线观看 | 久久久新视频 | 黄网免费| 国产精品国产馆在线真实露脸 | 免费影视在线观看 | 99精品视频免费观看 | 久久天天| 夜夜草| 欧美成人免费在线视频 | 免费视频中文字幕 | 天堂中文资源在线 | 久久一| 热久久免费视频 | 三级视频在线观看 | 久久久久se | 久久成人精品视频 | 久久国产精品免费视频 | 亚洲精品不卡 | 五月婷六月丁香 | 成人性视频在线播放 | av一区在线 | 国产精品不卡一区 | 超碰人人艹 | 日本a视频 | 亚洲一区 中文字幕 | 国产精品国产a级 | 久久久噜噜噜久久中文字幕色伊伊 | 七七婷婷婷婷精品国产 | 无码一区二区三区视频 | 伊人网站在线观看 | 人人性人人性碰国产 | www.色五月.com| 亚洲国产精品99久久久久久久久 | 在线免费观看黄网 |