Go語言 延 遲 語 句

????????延遲語句(defer)是Go 語言里一個非常有用的關鍵字,它能把資源的釋放語句與申請語句放到距離相近的位置,從而減少了資源泄漏的情況發生。

延遲語句是什么

????????defer 是Go 語言提供的一種用于注冊延遲調用的機制:讓函數或語句可以在當前函數執行完畢后(包括通過return 正常結束或者panic 導致的異常結束)執行。在需要釋放資源的場景非常有
用,可以很方便地在函數結束前做一些清理操作。在打開資源語句的下一行,直接使用defer 就可
以在函數返回前釋放資源,可謂相當有效。
defer 通常用于一些成對操作的場景:打開連接/關閉連接、加鎖/釋放鎖、打開文件/關閉文件
等。使用非常簡單:?

	f,err := os.Open(filename)if err != nil {panic(err)}if f != nil {defer f.Close()}

????????在打開文件的語句附近,用defer 語句關閉文件。這樣,在函數結束之前,會自動執行defer
后面的語句來關閉文件。注意,要先判斷f 是否為空,如果f 不為空,再調用f.Close()函數,避免出
現異常情況。
當然,defer 會有短暫延遲,對時間要求特別高的程序,可以避免使用它,其他情況一般可以忽略它帶來的延遲。特別是Go 1.14 又對defer 做了很大幅度的優化,效率提升了不少。
我們舉一個反面例子:?

r.mu.Lock()
rand.Intn(param)
r.mu.Unlock()

????????上面只有三行代碼,看起來這里不用 defer 執行 Unlock 并沒有什么問題。其實并不是這樣,
中間這行代碼rand.Intn(param)其實是有可能發生 panic 的,更嚴重的情況是,這段代碼很有可能被其他人修改,增加更多的邏輯,而這完全不可控。也就是說,在 Lock 和 Unlock 之間的代碼一旦出現異常情況導致 panic,就會形成死鎖。因此這里的邏輯是,即使是看起來非常簡單的代碼,使用 defer 也是有必要的,因為需求總是在變化,代碼也總會被修改。?

延遲語句的執行順序是什么?

????????每次 defer 語句執行的時候,會把函數“壓棧”,函數參數會被復制下來;當外層函數(注意不是代碼塊,如一個 for 循環塊并不是外層函數)退出時,defer 函數按照定義的順序逆序執行;如果 defer 執行的函數為nil,那么會在最終調用函數的時候產生 panic?

????????defer 語句并不會馬上執行,而是會進入一個棧,函數return 前,會按先進后出的順序執行。也就是說,最先被定義的defer 語句最后執行。先進后出的原因是后面定義的函數可能會依賴前面的資源,自然要先執行;否則,如果前面先執行了,那后面函數的依賴就沒有了,因而可能會出錯。
在 defer 函數定義時,對外部變量的引用有兩種方式:函數參數、閉包引用前者在 defer 定
義時就把值傳遞給 defer,并被 cache 起來
后者則會在 defer 函數真正調用時根據整個上下文確
定參數當前的值

defer 后面的函數在執行的時候,函數調用的參數會被保存起來,也就是復制了一份。真正執
行的時候,實際上用到的是這個復制的變量
,因此如果此變量是一個“值”,那么就和定義的時候
是一致的。如果此變量是一個“引用”,那就可能和定義的時候不一致。
舉個例子:

func main() {var whatever [3]struct{}for i := range whatever {defer func() {fmt.Println(i)}()}
}

執行結果:

2
1
0

????????defer 后面跟的是一個閉包(后面小節會講到),i 是“引用”類型的變量,for 循環結束后 i的值為 2,因此最后打印了2 1 0。

有了上面的基礎,再來看一個例子:

type number intfunc (n number) print()   { fmt.Println(n) }
func (n *number) pprint() { fmt.Println(*n) }
func main() {var n numberdefer n.print()defer n.pprint()defer func() { n.print() }()defer func() { n.pprint() }()n = 3
}

執行結果:

3
3
3
0

????????注意,defer 語句的執行順序和定義的順序相反。
第四個 defer 語句是閉包,引用外部函數的 n,最終結果是 3;第三個 defer 語句同上,也是閉包;第二個 defer 語句,n 是引用,最終求值是 3; 第一個 defer 語句,對 n 直接求值,開始的時候 n=0,所以最后是 0。
我們再來看兩個延伸情況。例如,下面的例子中,return 之后的 defer 語句會執行嗎?

func main() {defer func() {fmt.Println("before return")}()if true {fmt.Println("during return")return}defer func() {fmt.Println("after return")}()
}

運行結果:?

during return
before return

????????解析:return 之后的 defer 函數不能被注冊,因此不能打印出 after return。

????????第二個延伸示例則可以視為對defer 的原理的利用。某些情況下,會故意用到 defer 的“先求
值,再延遲調用”的性質
。想象這樣的場景:在一個函數里,需要打開兩個文件進行合并操作,合
并完成后,在函數結束前關閉打開的文件句柄。??

func mergeFile() error {// 打開文件一f, _ := os.Open("file1.txt")if f != nil {defer func(f io.Closer) {if err := f.Close(); err != nil {fmt.Printf("defer close file1.txt err %v\n", err)}}(f)}// 打開文件二f, _ = os.Open("file2.txt")if f != nil {defer func(f io.Closer) {if err := f.Close(); err != nil {fmt.Printf("defer close file2.txt err %v\n", err)}}(f)}// ……return nil
}

????????上面的代碼中就用到了 defer 的原理,defer 函數定義的時候,參數就已經復制進去了,之
后,真正執行 close() 函數的時候就剛好關閉的是正確的“文件”了,很巧妙。如果不這樣,將 f
當成函數參數傳遞進去的話,最后兩個語句關閉的就是同一個文件了:都是最后一個打開的文件。
在調用 close() 函數的時候,要注意一點:先判斷調用主體是否為空,否則可能會解引用了一
個空指針,進而 panic。?

?如何拆解延遲語句

????????如果 defer 像前面介紹的那樣簡單,這個世界就完美了。但事情總是沒這么簡單,defer 用得
不好,會陷入泥潭。
避免陷入泥潭的關鍵是必須深刻理解下面這條語句:

return xxx

????????上面這條語句經過編譯之后,實際上生成了三條指令:
??????1)設置返回值 = xxx。
2)調用 defer 函數。
3)空的 return。講返回值返回


第 1 和第3 步是 return 語句生成的指令,也就是說return 并不是一條原子指令;第 2 步是
defer 定義的語句,這里可能會操作返回值,從而影響最終結果。
下面來看兩個例子,試著將 return 語句和 defer 語句拆解到正確的順序。
第一個例子:?

func f() (res int) {t := 5defer func() {t = t + 5}()return t
}

拆解后:

func f() (res int) {t := 5// 1. 賦值指令res = t// 2. defer 被插入到賦值與返回之間執行,這個例子中返回值 res 沒被修改過func() {t = t + 5}// 3. 空的return 指令return
}

????????這里第二步實際上并沒有操作返回值 r,因此,main 函數中調用 f() 得到 5。?

????????第二個例子:

func f() (res int) {defer func(res int) {res = res + 5}(res)return 1
}

????????拆解后:

func f() (res int) {// 1. 賦值res = 1// 2. 這里改的 res 是之前傳進去的 res,不會改變要返回的那個 res值func(res int) {res = res + 5}(res)// 3. 空的returnreturn
}

????????第二步,改變的是傳值進去的 r,是形參的一個復制值,不會影響實參 r。因此,main 函數中
需要調用f()得到1。?

? ? ? ? 第三個例子:

package mainimport "fmt"func main() {res := deferRun()fmt.Println(res)
}func deferRun() (res int) {num := 1  defer func() {res++}()  return num
}

運行結果:

2

????????在本例中,第一步是將result的值設置為num,此時還未執行defernum的值是1,所以result被設置為1,然后再執行defer語句將result+1,最終將result返回,所以會打印出?2

????????如果把defer中的res++改成num++

func deferRun() (res int) {num := 1defer func() {num++}()  return num
}

運行結果:?

1

????????第一步是將result的值設置為num,此時還未執行defernum的值是1,所以result被設置為1,然后再執行defer 即num+1,要返回的result并沒有變最終將result返回,所以會打印出?1。?

如何確定延遲語句的參數

????????defer 語句表達式的值在定義時就已經確定了。下面通過三個不同的函數來理解:

func f1() {var err errordefer fmt.Println(err)err = errors.New("defer1 error")return
}
func f2() {var err errordefer func() {fmt.Println(err)}()err = errors.New("defer2 error")return
}
func f3() {var err errordefer func(err error) {fmt.Println(err)}(err)err = errors.New("defer3 error")return
}
func main() {f1()f2()f3()
}

????????運行結果:?

<nil>
defer2 error
<nil>

????????第 1 和第3 個函數中,因為作為參數,err 在函數定義的時候就會求值,并且定義的時候 err
的值都是 nil,所以最后打印的結果都是 nil;第 2 個函數的參數其實也會在定義的時候求值,但
第 2 個例子中是一個閉包,它引用的變量 err 在執行的時候值最終變成 defer2 error 了。

func deferrun3() {num := 1defer func() {fmt.Println(num)}()num++return
}

運行結果:?原理同上述第二個例子,也是閉包

2

????????現實中第 3 個函數比較容易犯錯誤,在生產環境中,很容易寫出這樣的錯誤代碼,導致最后
defer 語句沒有起到作用,造成一些線上事故,要特別注意。

閉包是什么


閉包是由函數及其相關引用環境組合而成的實體,即:閉包=函數+引用環境
一般的函數都有函數名,而匿名函數沒有。匿名函數不能獨立存在,但可以直接調用或者賦值于某個變量。匿名函數也被稱為閉包,一個閉包繼承了函數聲明時的作用域。在 Go 語言中,所有的匿名函數都是閉包
有個不太恰當的例子:可以把閉包看成是一個類,一個閉包函數調用就是實例化一個類。閉包在運行時可以有多個實例,它會將同一個作用域里的變量和常量捕獲下來,無論閉包在什么地方被調用(實例化)時,都可以使用這些變量和常量。而且,閉包捕獲的變量和常量是引用傳遞,不是值傳遞。
舉個簡單的例子:

func main() {var a = Accumulator()fmt.Printf("%d\n", a(1))fmt.Printf("%d\n", a(10))fmt.Printf("%d\n", a(100))fmt.Println("------------------------")var b = Accumulator()fmt.Printf("%d\n", b(1))fmt.Printf("%d\n", b(10))fmt.Printf("%d\n", b(100))
}
func Accumulator() func(int) int {var x intreturn func(delta int) int {fmt.Printf("(%+v, %+v) - ", &x, x)x += deltareturn x}
}

執行結果是:?

(0xc420014070, 0) - 1
(0xc420014070, 1) - 11
(0xc420014070, 11) - 111
------------------------
(0xc4200140b8, 0) - 1
(0xc4200140b8, 1) - 11
(0xc4200140b8, 11) – 111

????????閉包引用了 x 變量,a,b 可看作 2 個不同的實例,實例之間互不影響。實例內部,x 變量
是同一個地址,因此具有“累加效應”。?

延遲語句如何配合恢復語句

????????Go 語言被詬病多次的就是它的 error,實際項目里經常出現各種 error 滿天飛,正常的代碼邏
輯里有很多 error 處理的代碼塊。函數總是會返回一個 error,留給調用者處理;而如果是致命的錯
誤,比如程序執行初始化的時候出問題,最好直接 panic 掉,避免上線運行后出更大的問題。
有些時候,需要從異常中恢復。比如服務器程序遇到嚴重問題,產生了 panic,這時至少可以
在程序崩潰前做一些“掃尾工作”,比如關閉客戶端的連接,防止客戶端一直等待等;并且單個請求導致的 panic,也不應該影響整個服務器程序的運行。

recover異常捕獲

????????異常其實就是指程序運行過程中發生了panic,那么我們為了不讓程序報錯退出,可以在程序中加入recover機制,將異常捕獲,打印出異常,這樣也方便我們定位錯誤。而捕獲的方式我們之前在講defer的時候也提到過,一般是用recoverdefer搭配使用來捕獲異常。
下面請看個具體例子:

func main() {         defer func() {                 if error:=recover();error!=nil{   fmt.Println("出現了panic,使用reover獲取信息:",error)   }         }()         fmt.Println("11111111111")        panic("出現panic")         fmt.Println("22222222222") }

運行結果:

11111111111
出現了panic,使用reover獲取信息: 出現panic

????????注意,這里有了recover之后,程序不會在panic出中斷,再執行完panic之后,會接下來執行defer recover函數,但是當前函數panic后面的代碼不會被執行,但是調用該函數的代碼會接著執行。
如果我們在main函數中未加入defer func(){...},當我們的程序運行到底8行時就會panic掉,而通常在我們的業務程序中對于程序panic是不可容忍的,我們需要程序健壯的運行,而不是是不是因為一些panic掛掉又被拉起,所以當發生panic的時候我們要讓程序能夠繼續運行,并且獲取到發生panic的具體錯誤,這就可以用上述方法。

panic傳遞

????????當一個函數發生了panic之后,若在當前函數中沒有recover,會一直向外層傳遞直到主函數,如果遲遲沒有recover的話,那么程序將終止。如果在過程中遇到了最近的recover,則將被捕獲。
看下面例子:

package mainimport "fmt"func testPanic1(){fmt.Println("testPanic1上半部分")testPanic2()fmt.Println("testPanic1下半部分")
}func testPanic2(){defer func() {recover()}()fmt.Println("testPanic2上半部分")testPanic3()fmt.Println("testPanic2下半部分")
}func testPanic3(){fmt.Println("testPanic3上半部分")panic("在testPanic3出現了panic")fmt.Println("testPanic3下半部分")
}func main() {fmt.Println("程序開始")testPanic1()fmt.Println("程序結束")
}

運行結果:

程序開始
testPanic1上半部分
testPanic2上半部分
testPanic3上半部分
testPanic1下半部分
程序結束

解析:
調用鏈:main-->testPanic1-->testPanic2-->testPanic3,但是在testPanic3中發現了一個panic,由于testPanic3沒有recover,向上找,在testPanic2中找到了recoverpanic被捕獲了,程序接著運行,由于testPanic3發生了panic,所以不再繼續運行,函數跳出返回到testPanic2testPanic2中捕獲到了panic,也不會再繼續執行,跳出函數testPanic2,到了testPanic1接著運行。

????????所以recoverpanic可以總結為以下兩點:

????????這里的調用鏈指的是同一個函數中(如果panic是在另外一個go程中,是捕獲不到的。即一個go程是無法捕獲到另一個go程中的panic)

  1. recover()只能恢復當前函數級以當前函數為首的調用鏈中的函數中的panic(),恢復后調用當前函數結束,但是調用此函數的函數繼續執行
  2. 函數發生了panic之后會一直向上傳遞,如果直至main函數都沒有recover(),程序將終止,如果是碰見了recover(),將被recover捕獲。

defer...recover

? ? ? ? panic 會停掉當前正在執行的程序,而不只是當前線程。在這之前,它會有序地執行完當前線
程 defer 列表里的語句
,其他協程里定義的 defer 語句不作保證。所以在 defer 里定義一個recover 語句,防止程序直接掛掉,就可以起到類似 Java 里 try...catch 的效果。
注意,recover() 函數只在 defer 的函數中直接調用才有效。例如:

func main() {defer fmt.Println("defer main")var user = os.Getenv("USER_")go func() {defer func() {fmt.Println("defer caller")if err := recover(); err != nil {fmt.Println("recover success. err: ", err)}}()func() {defer func() {fmt.Println("defer here")}()if user == "" {panic("should set user env.")}// 此處不會執行fmt.Println("after panic")}()}()time.Sleep(100)fmt.Println("end of main function")
}

程序的執行結果:?

defer here
defer caller
recover success. err: should set user env.
end of main function
defer main

????????代碼中的 panic 最終會被 recover 捕獲到。這樣的處理方式在一個 http server 的主流程常常
會被用到。一次偶然的請求可能會觸發某個 bug,這時用 recover 捕獲 panic,穩住主流程,不影
響其他請求。
同樣,我們再來看幾個延伸示例。這些例子都與 recover() 函數的調用位置有關。
考慮以下寫法,程序是否能正確 recover 嗎?如果不能,原因是什么:?

func main() {defer f()panic(404)
}
func f() {if e := recover(); e != nil {fmt.Println("recover")return}
}

????????能。在 defer 的函數中調用,生效。?

func main() {recover()panic(404)
}

????????不能。直接調用 recover,返回 nil。?

func main() {defer recover()panic(404)
}

????????不能。要在 defer 函數里調用 recover。?

func main() {defer func() {if e := recover(); e != nil {fmt.Println("recover")}}()panic(404)
}

????????能。在 defer 的函數中調用,生效。?

func main() {defer func() {recover()}()panic(404)
}

????????能。在 defer 的函數中調用,生效。?

func main() {defer func() {defer func() {recover()}()}()panic(404)
}

????????不能。多重 defer 嵌套。?

為什么無法從父goroutine 恢復子goroutine 的panic

????????對于這個問題,其實更普遍問題是:為什么無法 recover 其他 goroutine 里產生的 panic??

????????為什么不能從父 goroutine 中恢復子 goroutine 的 panic?或者一般地說,為什么某個
goroutine 不能捕獲其他 goroutine 內產生的 panic?

????????是設計使然:因為goroutine 被設計為一個獨立的代碼執行單元,擁有自己的執行棧,不與其他 goroutine 共享任何數據。這意味著,無法讓 goroutine 擁有返回值、也無法讓 goroutine 擁有自身的 ID 編號等。若需要與其他 goroutine 產生交互,要么可以使用 channel 的方式與其他 goroutine 進行通信,要么通過共享內存同步方式對共享的內存添加讀寫鎖。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/94395.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/94395.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/94395.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【go 】數組的多種初始化方式與操作

在 Go 語言中&#xff0c;數組是一種固定長度的數據結構&#xff0c;用于存儲相同類型的元素。以下是 Go 中數組的多種初始化方式&#xff0c;結合搜索結果整理如下&#xff1a; &#xff08;一&#xff09;使用 var 關鍵字聲明并初始化數組 使用 var 關鍵字聲明數組時&#xf…

基于Java+MySQL 實現(Web)網上商城

悅桔拉拉商城1. 課設目的可以鞏固自己之前所學的知識&#xff0c;以及學習更多的新知識。可以掌握業務流程&#xff0c;學習工作的流程。2. 開發環境硬件環境&#xff1a;Window11 電腦、Centos7.6 服務器軟件環境&#xff1a;IntelliJ IDEA 2021.1.3 開發工具JDK 16 運行環境M…

高并發搶單系統核心實現詳解:Redisson分布式鎖實戰

一、方法整體流程解析 #mermaid-svg-MROZ2xF7WaNPaztA {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-MROZ2xF7WaNPaztA .error-icon{fill:#552222;}#mermaid-svg-MROZ2xF7WaNPaztA .error-text{fill:#552222;strok…

Android12 User版本開啟adb root, adb remount, su, 關閉selinux

開啟adb root 直接看adb源碼&#xff1a; __android_log_is_debuggable就是判斷ro.debuggable屬性值&#xff0c;感興趣可以在 源碼下grep下實現看看。auth_required :在adb源碼下定義的全局變量&#xff0c;默認等于true,。看名字就是是否需要用戶授權的flag, 這里不再繼續跟…

金融專業高分簡歷撰寫指南

一、金融求職簡歷原則&#xff1a;深度與亮點并存在金融行業求職時&#xff0c;一份出色的簡歷需突出經歷深度與亮點。01 教育背景需如實填寫畢業院校、專業、GPA及所學課程。金融行業不少公司對求職者學校和學歷有嚴格標準&#xff0c;如“985”“211”院校或碩士以上學歷等。…

專題:2025生命科學與生物制藥全景報告:產業圖譜、投資方向及策略洞察|附130+份報告PDF、原數據表匯總下載

原文鏈接&#xff1a;https://tecdat.cn/?p43526 過去一年&#xff0c;全球生命科學VC融資回暖至1021.5億美元&#xff0c;并購交易雖下滑23%卻聚焦關鍵賽道&#xff0c;創新藥管線中GLP-1受體激動劑以170億美元市場規模領跑&#xff0c;AI技術將研發周期縮短60%……這些數據背…

Compose筆記(四十)--ClickableText

這一節主要了解一下Compose中的ClickableText&#xff0c;在Jetpack Compose中&#xff0c;ClickableText是用于創建可點擊文本的組件&#xff0c;其核心功能是通過聲明式語法將文本設置為交互式元素&#xff0c;用戶點擊時可觸發特定操作。簡單總結如下:API含義 text&#xff…

面試必刷的數組三連:原地刪除與合并

堅持用 清晰易懂的圖解 多語言代碼&#xff0c;讓每道題變得簡單&#xff01; 呆頭個人主頁詳情 呆頭個人Gitee代碼倉庫 呆頭詳細專欄系列 座右銘&#xff1a; “不患無位&#xff0c;患所以立。” 面試必刷的數組三連&#xff1a;原地刪除與合并前言目錄1.移除元素2.刪除有序…

力扣經典算法篇-41-旋轉圖像(輔助數組法,原地旋轉法)

1、題干 給定一個 n n 的二維矩陣 matrix 表示一個圖像。請你將圖像順時針旋轉 90 度。 你必須在 原地 旋轉圖像&#xff0c;這意味著你需要直接修改輸入的二維矩陣。請不要 使用另一個矩陣來旋轉圖像。 示例 1&#xff1a;輸入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]]…

譯|用戶增長策略如何使用因果機器學習的案例

來自上傳文件中的文章《[Causal Machine Learning for Growth: Loyalty Programs, LTV, and What to Do When You Can’t Experiment | by Torty Sivill | Towards AI]》 本文探討了當 A/B 測試不可行時&#xff0c;如何利用因果推斷從歷史數據中獲取洞察。技術亮點在于通過構建…

java~final關鍵字

final關鍵字final基本介紹final的使用細節final基本介紹 final是最終的意思&#xff0c;可以修飾類&#xff0c;屬性&#xff0c;方法&#xff0c;局部變量什么時候會要使用到final呢&#xff1f; 1.想要類不被繼承時 2.不希望類的某個屬性的值被改變時 3.不想父類的某個方法被…

Node.js(四)之數據庫與身份認證

數據庫與身份認證 目錄 數據庫與身份認證 十三、數據庫的基本概念 13.1 什么是數據庫 13.2 常見的數據庫及分類 13.3 傳統型數據庫的數據組織結構 1. Excel 的數據組織結構 2. 傳統型數據庫的數據組織結構 3. 實際開發中庫、表、行、字段的關系 十四、安裝并配置MySQ…

SpringBoot+SpringMVC常用注解

文章目錄發展歷程項目創建項目結構入門案例配置文件的兩種方式&#xff1a;只能使用一種創建項目二入門案例常用知識及注解Controller:類上面加&#xff0c;SpringMVC的注解GetMapping:方法上面加Spring框架的兩項核心功能Component:組件。控制反轉&#xff0c;加在業務類上面&…

標準GS相位恢復算法

標準GS相位恢復算法詳解與MATLAB實現 Gerchberg-Saxton (GS) 算法是一種經典的相位恢復方法&#xff0c;廣泛應用于光學成像、衍射成像和全息技術等領域。該算法通過迭代過程從未知相位的強度測量中恢復相位信息。 算法原理 GS算法的核心思想是利用傅里葉變換關系在空間域和頻率…

【Linux網絡編程基礎--socket地址API】

一、主機字節序和網絡字節序主機字節序&#xff08;Host Byte Order&#xff09;&#xff1a;你當前電腦的內存字節順序&#xff08;比如 x86 是小端&#xff09;網絡字節序&#xff08;Network Byte Order&#xff09;&#xff1a;統一規定為大端序&#xff08;高位字節在高位…

Linux路徑MTU發現(Path MTU Discovery, PMTU)

Linux路徑MTU發現&#xff08;Path MTU Discovery, PMTU&#xff09;機制是TCP/IP協議棧中確保數據包高效傳輸的核心技術。其核心目標是動態探測源主機到目的主機路徑上的最小MTU&#xff08;Maximum Transmission Unit&#xff09;&#xff0c;從而避免IP分片&#xff0c;提升…

【MySQL進階】------MySQL程序

MySQL程序簡介 MySQL安裝完成通常會包含如下程序&#xff1a; Linux系統程序?般在 /usr/bin?錄下&#xff0c;可以通過命令查看&#xff1a; windows系統?錄&#xff1a;你的安裝路徑\MySQL Server 8.0\bin&#xff0c;可以通過命令查看&#xff1a; 每個 MySQL 程序都有許…

Linux大頁內存導致服務內存不足

Linux大頁內存導致服務內存不足的解決方法 大頁內存&#xff08;Huge Pages&#xff09;是Linux內核提供的一種機制&#xff0c;用于減少TLB&#xff08;轉換后備緩沖區&#xff09;的壓力&#xff0c;提高內存訪問性能。然而&#xff0c;如果配置不當&#xff0c;大頁內存可能…

超寬帶測距+測角+無線通信一體化模組:智能門鎖、智能遙控器、AR頭戴、智能穿戴

超寬帶測距測角無線通信一體化模組&#xff1a;智能門鎖、智能遙控器、AR頭戴、智能穿戴UWB測距測角技術&#xff0c;因其高精度、低延遲、抗干擾能力&#xff0c;正廣泛應用于“人-物-設備”的空間感知場景&#xff0c;成為構建智能空間和精準互動的重要底層技術。代表廠商與產…

基于單片機空氣質量檢測/氣體檢測系統

傳送門 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品題目速選一覽表 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品題目功能速覽 概述 隨著環境污染問題日益嚴重&#xff0c;空氣質量監測成為社會關注的焦點。基于單片機的空氣質量檢…