第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Golang,goroutines:恐慌:運行時錯誤:無效的內(nèi)存地址

Golang,goroutines:恐慌:運行時錯誤:無效的內(nèi)存地址

Go
開滿天機 2021-12-07 18:46:45
我對 golang 比較陌生,并試圖理解主要原理并使用 chanels 編寫基于 gouroutines 的代碼。在我使用的其他語言中沒有這樣的工具,我想知道會出現(xiàn)像恐慌這樣的錯誤......我的代碼:package mainimport "fmt"import (    "time")type Work struct {    x,y,z int}func worker(in <-chan *Work, out chan<- *Work){    for w := range in {        w.z = w.x + w.y        time.Sleep(time.Duration(w.z))        out <-w    }}func sendWork(in chan <- *Work){    var wo *Work    wo.x, wo.y, wo.z = 1,2,3    in <- wo    in <- wo    in <- wo    in <- wo    in <- wo}func receiveWork(out <-chan *Work ) []*Work{    var  slice []*Work    for el := range out {        slice = append(slice, el)    }    return slice}func main() {    in, out := make(chan *Work), make(chan *Work)    for i := 0; i<3; i++{        go worker(in, out)    }    go sendWork(in)    data := receiveWork(out)    fmt.Printf("%v", data)}但在終端我得到了這個:panic: runtime error: invalid memory address or nil pointer dereference[signal 0xc0000005 code=0x1 addr=0x0 pc=0x401130]goroutine 8 [running]:main.sendWork(0xc0820101e0)        C:/temp/gocode/src/helloA/helloA.go:21 +0x20created by main.main        C:/temp/gocode/src/helloA/helloA.go:43 +0xe4goroutine 1 [chan receive]:main.receiveWork(0xc082010240, 0x0, 0x0, 0x0)        C:/temp/gocode/src/helloA/helloA.go:31 +0x80main.main()        C:/temp/gocode/src/helloA/helloA.go:45 +0xf2goroutine 5 [chan receive]:main.worker(0xc0820101e0, 0xc082010240)        C:/temp/gocode/src/helloA/helloA.go:12 +0x55created by main.main        C:/temp/gocode/src/helloA/helloA.go:40 +0xafgoroutine 6 [runnable]:main.worker(0xc0820101e0, 0xc082010240)        C:/temp/gocode/src/helloA/helloA.go:11created by main.main        C:/temp/gocode/src/helloA/helloA.go:40 +0xafgoroutine 7 [runnable]:main.worker(0xc0820101e0, 0xc082010240)        C:/temp/gocode/src/helloA/helloA.go:11created by main.main        C:/temp/gocode/src/helloA/helloA.go:40 +0xaf我如何確定問題出在哪里,以及如何很好地關(guān)閉 gouroutines,而不是將它們作為進程...
查看完整描述

1 回答

?
陪伴而非守候

TA貢獻1757條經(jīng)驗 獲得超8個贊

nil 取消引用:

您正在嘗試訪問由指針引用的結(jié)構(gòu),但該指針尚未設(shè)置為該結(jié)構(gòu)的實例。您必須聲明一個可以指向指針的結(jié)構(gòu)。


錯誤首先出現(xiàn)在這里:


wo.x, wo.y, wo.z = 1,2,3

您嘗試寫入指向的對象的位置wo。但是這里的指針為零;它實際上并不是指向Work. 我們必須創(chuàng)建該實例,以便我們可以指向它。


指向結(jié)構(gòu)體的指針的 nil 值為nil。如果你沒有為它聲明一個結(jié)構(gòu)體實例,它指向 nil。


var wo *Work

聲明wo為類型的指針Work到nil。


 var wo = &Work{}

聲明wo為指向 的Work新實例的類型指針Work。


或者您可以使用較短的語法:


wo := &Work{}

至于死鎖:


當(dāng)我們關(guān)閉一個通道時,該通道上的范圍循環(huán)將退出。在func worker我們范圍內(nèi)的一個頻道。當(dāng)這個通道關(guān)閉時,worker(s) 將退出。


為了等待所有工人完成處理,我們使用sync.WaitGroup. 這是在繼續(xù)之前等待一組 goroutine 完成運行的簡單方法。


首先你告訴等待組它應(yīng)該等待多少個 goroutine。


wg.Add(3)

然后你等待:


wg.Wait()

直到所有的 goroutine 都調(diào)用了


wg.Done()

當(dāng)他們完成執(zhí)行時他們會這樣做。


在這種情況下,我們需要在所有 worker 執(zhí)行完畢后關(guān)閉輸出通道,以便func receiveWork可以退出其 for range 循環(huán)。我們可以通過為此任務(wù)啟動一個新的 goroutine 來做到這一點:


go func() {

    wg.Wait()

    close(out)

}()

這是整個文件,經(jīng)過這些編輯:


package main


import (

    "fmt"

    "sync"

    "time"

)


type Work struct {

    x, y, z int

}


func worker(in <-chan *Work, out chan<- *Work, wg *sync.WaitGroup) {

    for w := range in {

        w.z = w.x + w.y

        time.Sleep(time.Duration(w.z))

        out <- w

    }

    wg.Done() // this worker is now done; let the WaitGroup know.

}


func sendWork(in chan<- *Work) {

    wo := &Work{x: 1, y: 2, z: 3} // more compact way of initializing the struct

    in <- wo

    in <- wo

    in <- wo

    in <- wo

    in <- wo

    close(in) // we are done sending to this channel; close it

}


func receiveWork(out <-chan *Work) []*Work {

    var slice []*Work

    for el := range out {

        slice = append(slice, el)

    }

    return slice

}


func main() {

    var wg sync.WaitGroup

    in, out := make(chan *Work), make(chan *Work)

    wg.Add(3) // number of workers

    for i := 0; i < 3; i++ {

        go worker(in, out, &wg)

    }


    go sendWork(in)


    go func() {

        wg.Wait()

        close(out)

    }()


    data := receiveWork(out)


    fmt.Printf("%v", data)

}

哪些輸出:


[0x104382f0 0x104382f0 0x104382f0 0x104382f0 0x104382f0]

這可能不是您所期望的。然而,它確實突出了此代碼的一個問題。稍后再談。


如果你想打印結(jié)構(gòu)體的內(nèi)容,你可以停止使用指向 的指針Work,或者遍歷切片的元素并逐個打印它們,如下所示:


for _, w := range data {

    fmt.Printf("%v", w)

}

輸出:


&{1 2 3}&{1 2 3}&{1 2 3}&{1 2 3}&{1 2 3}

Go 在打印時不會跟隨指針向下一步,以避免無限遞歸,因此您必須手動執(zhí)行此操作。


比賽條件:


由于您*Work在通道中多次發(fā)送指向同一個實例的指針,因此多個 goroutine 在沒有同步的情況下同時訪問同一個實例。您可能想要的是停止使用指針,而使用值。Work而不是*Work.


如果你想使用指針,也許因為Work它實際上非常大,你可能想要創(chuàng)建多個實例,*Work所以你只將它發(fā)送到一個 goroutine。


以下是圍棋比賽檢測器對代碼的評價:


C:/Go\bin\go.exe run -race C:/gopath/src/github.com/drathier/scratchpad/go/main/main.go

[0xc0820403c0 0xc0820403c0 0xc0820403c0 0xc0820403c0 0xc0820403c0]==================

WARNING: DATA RACE

Write by goroutine 6:

  main.worker()

      C:/gopath/src/github.com/drathier/scratchpad/go/main/main.go:15 +0x8a


Previous write by goroutine 8:

  main.worker()

      C:/gopath/src/github.com/drathier/scratchpad/go/main/main.go:15 +0x8a


Goroutine 6 (running) created at:

  main.main()

      C:/gopath/src/github.com/drathier/scratchpad/go/main/main.go:45 +0x10c


Goroutine 8 (running) created at:

  main.main()

      C:/gopath/src/github.com/drathier/scratchpad/go/main/main.go:45 +0x10c

==================

Found 1 data race(s)

exit status 66

在這一行:


w.z = w.x + w.y

所有 goroutine 都在w.z同時修改,所以如果它們嘗試將不同的值寫入w.z,則無法知道實際最終會出現(xiàn)什么值。再一次,這很容易通過創(chuàng)建 的多個實例*Work或使用值而不是指針來解決:Work。


查看完整回答
反對 回復(fù) 2021-12-07
  • 1 回答
  • 0 關(guān)注
  • 168 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號