Go 中共享變數:了解兩種情況的區別
在Go 中,goroutines 是輕量級的並發任務,可以共享記憶體並使用以下方式進行通訊管道。 Goroutines 之間的變數共享需要小心處理,以避免資料競爭問題。
考慮以下Go 程式:
<code class="go">package main import ( "fmt" "sync" ) func main() { var wg sync.WaitGroup for i := 0; i < 5; i++ { wg.Add(1) x := i go func() { defer wg.Done() fmt.Println(x) }() } wg.Wait() fmt.Println("Done") }</code>
執行時,程式會列印預期的輸出:
4 0 1 3 2
在這種情況下,每個goroutine 都有自己的變數x 副本,該副本在建立goroutine 時使用i 的當前值進行初始化。這是因為 x 是在匿名函數中聲明的,並且其範圍僅限於該函數。
現在,考慮對程式進行輕微修改:
<code class="go">package main import ( "fmt" "sync" ) func main() { var wg sync.WaitGroup for i := 0; i < 5; i++ { wg.Add(1) go func() { defer wg.Done() fmt.Println(i) }() } wg.Wait() fmt.Println("Done") }</code>
這次,輸出變成:
5 5 5 5 5
解釋在於變數i 在goroutine 中使用的方式。由於 i 是在匿名函數外部聲明的,因此它在所有 goroutine 之間共用。在這種情況下,當每個 goroutine 執行 fmt.Println(i) 時,它會列印 i 的最終值,即 5。
為了驗證這一點,我們可以在其中添加 x 和 i 的記憶體位址的列印goroutine。輸出顯示x 對於每個goroutine 有不同的位址,而i 對於所有goroutine 有相同的位址:
0xc0420301e0 0xc0420301f8 0xc0420301e8 0xc0420301f0 0xc042030200 0xc042030208
綜上所述,兩種情況之間變數共享的差異源自於變數的範圍在匿名函數中聲明。當一個變數在匿名函數中宣告時,它對於該 goroutine 是私有的。另一方面,在匿名函數外部宣告的變數在所有 goroutine 之間共用。
以上是為什麼在 Go 中共享變數會根據匿名函數中的範圍導致不同的輸出?的詳細內容。更多資訊請關注PHP中文網其他相關文章!