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

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問(wèn)題,去搜搜看,總會(huì)有你想問(wèn)的

程序使用等待組進(jìn)入死鎖

程序使用等待組進(jìn)入死鎖

Go
繁星coding 2022-07-18 16:56:33
我正在編寫(xiě)一個(gè)程序,它讀取名為 orders.csv 的文件中的訂單號(hào)列表,并將其與文件夾中存在的其他 csv 文件進(jìn)行比較。問(wèn)題是即使使用等待組它也會(huì)陷入死鎖,我不知道為什么。出于某種原因,stackoverflow 說(shuō)我的帖子主要是代碼,所以我必須添加這一行,因?yàn)槿绻腥讼霂椭艺{(diào)試我遇到的這個(gè)問(wèn)題,整個(gè)代碼都是必要的。package mainimport (    "bufio"    "fmt"    "log"    "os"    "path/filepath"    "strings"    "sync")type Files struct {    filenames []string}type Orders struct {    ID []string}var ordersFilename string = "orders.csv"func main() {    var (        ordersFile *os.File        files       Files        orders     Orders        err        error    )    mu := new(sync.Mutex)    wg := &sync.WaitGroup{}    wg.Add(1)    if ordersFile, err = os.Open(ordersFilename); err != nil {        log.Fatalln("Could not open file: " + ordersFilename)    }    orders = getOrderIDs(ordersFile)    files.filenames = getCSVsFromCurrentDir()    var filenamesSize = len(files.filenames)    var ch = make(chan map[string][]string, filenamesSize)    var done = make(chan bool)    for i, filename := range files.filenames {        go func(currentFilename string, ch chan<- map[string][]string, i int, orders Orders, wg *sync.WaitGroup, filenamesSize *int, mu *sync.Mutex, done chan<- bool) {            wg.Add(1)            defer wg.Done()            checkFile(currentFilename, orders, ch)            mu.Lock()            *filenamesSize--            mu.Unlock()            if i == *filenamesSize {                done <- true                close(done)            }        }(filename, ch, i, orders, wg, &filenamesSize, mu, done)    }    select {    case str := <-ch:        fmt.Printf("%+v\n", str)    case <-done:        wg.Done()        break    }    wg.Wait()    close(ch)}
查看完整描述

3 回答

?
夢(mèng)里花落0921

TA貢獻(xiàn)1772條經(jīng)驗(yàn) 獲得超6個(gè)贊

  1. 第一個(gè)問(wèn)題是wg.Addalways 必須在它所代表的 goroutine(s) 之外。如果不是,則 wg.Wait可能會(huì)在 goutine 實(shí)際開(kāi)始運(yùn)行(并被調(diào)用wg.Add)之前調(diào)用該調(diào)用,因此會(huì)“認(rèn)為”沒(méi)有什么可等待的。

  2. 代碼的第二個(gè)問(wèn)題是它等待例程完成的方式有多種。有渠道WaitGroup,有done渠道。僅使用其中之一。哪一個(gè)還取決于如何使用 goroutines 的結(jié)果。在這里,我們來(lái)到下一個(gè)問(wèn)題。

  3. 第三個(gè)問(wèn)題是收集結(jié)果。目前,該代碼僅打印/使用來(lái)自 goroutine 的單個(gè)結(jié)果。for { ... }在選擇周?chē)胖靡粋€(gè)循環(huán),如果通道關(guān)閉,則使用它return來(lái)跳出循環(huán)。done(請(qǐng)注意,您不需要在done頻道上發(fā)送任何內(nèi)容,關(guān)閉它就足夠了。)

改進(jìn)版 0.0.1

所以這里的第一個(gè)版本(包括其他一些“代碼清理”)帶有done用于關(guān)閉和WaitGroup刪除的通道:

func main() {

    ordersFile, err := os.Open(ordersFilename)

    if err != nil {

        log.Fatalln("Could not open file: " + ordersFilename)

    }


    orders := getOrderIDs(ordersFile)


    files := Files{

        filenames: getCSVsFromCurrentDir(),

    }


    var (

        mu = new(sync.Mutex)

        filenamesSize = len(files.filenames)

        ch = make(chan map[string][]string, filenamesSize)

        done = make(chan bool)

    )


    for i, filename := range files.filenames {

        go func(currentFilename string, ch chan<- map[string][]string, i int, orders Orders, filenamesSize *int, mu *sync.Mutex, done chan<- bool) {

            checkFile(currentFilename, orders, ch)

            mu.Lock()

            *filenamesSize--

            mu.Unlock()

            // TODO: This also accesses filenamesSize, so it also needs to be protected with the mutex:

            if i == *filenamesSize {

                done <- true

                close(done)

            }

        }(filename, ch, i, orders, &filenamesSize, mu, done)

    }


    // Note: closing a channel is not really needed, so you can omit this:

    defer close(ch)

    for {

        select {

        case str := <-ch:

            fmt.Printf("%+v\n", str)

        case <-done:

            return

        }

    }

}

改進(jìn)版 0.0.2

但是,在您的情況下,我們有一些優(yōu)勢(shì)。我們確切地知道我們啟動(dòng)了多少個(gè) goroutine,因此也知道我們期望有多少結(jié)果。(當(dāng)然,如果每個(gè) goroutine 返回一個(gè)當(dāng)前代碼所做的結(jié)果。)這為我們提供了另一種選擇,因?yàn)槲覀兛梢允褂昧硪粋€(gè)具有相同迭代次數(shù)的 for 循環(huán)來(lái)收集結(jié)果:

func main() {

    ordersFile, err := os.Open(ordersFilename)

    if err != nil {

        log.Fatalln("Could not open file: " + ordersFilename)

    }


    orders := getOrderIDs(ordersFile)


    files := Files{

        filenames: getCSVsFromCurrentDir(),

    }


    var (

        // Note: a buffered channel helps speed things up. The size does not need to match the size of the items that will

        //   be passed through the channel. A fixed, small size is perfect here.

        ch = make(chan map[string][]string, 5)

    )


    for _, filename := range files.filenames {

        go func(filename string) {

            // orders and channel are not variables of the loop and can be used without copying

            checkFile(filename, orders, ch)

        }(filename)

    }


    for range files.filenames {

        str := <-ch

        fmt.Printf("%+v\n", str)

    }

}

簡(jiǎn)單很多,不是嗎?希望有幫助!


查看完整回答
反對(duì) 回復(fù) 2022-07-18
?
慕的地8271018

TA貢獻(xiàn)1796條經(jīng)驗(yàn) 獲得超4個(gè)贊

這段代碼有很多錯(cuò)誤。

  1. 您使用 WaitGroup 錯(cuò)誤。Add 必須在主 goroutine 中調(diào)用,否則有可能在所有 Add 調(diào)用完成之前調(diào)用 Wait。

  2. 在初始化與 Done() 調(diào)用不匹配的 WaitGroup 之后,有一個(gè)無(wú)關(guān)的 Add(1) 調(diào)用,因此 Wait 永遠(yuǎn)不會(huì)返回(假設(shè)上面的點(diǎn)是固定的)。

  3. 您同時(shí)使用 WaitGroup 和 done 通道來(lái)表示完成。這充其量是多余的。

  4. 您正在讀取 filenamesSize 而沒(méi)有持有鎖(在if i == *filenamesSize語(yǔ)句中)。這是一個(gè)競(jìng)爭(zhēng)條件。

  5. 首先,這種i == *filenamesSize情況毫無(wú)意義。Goroutines 以任意順序執(zhí)行,所以你不能確定 i == 0 的 goroutine 是最后一個(gè)減少 filenamesSize

這可以通過(guò)去掉大部分同步原語(yǔ)并在所有 goroutine 完成后簡(jiǎn)單地關(guān)閉 ch 通道來(lái)簡(jiǎn)化:

func main() { 

    ch := make(chan map[string][]string)

    var wg WaitGroup


    for _, filename := range getCSVsFromCurrentDir() { 

        filename := filename // capture loop var

        wg.Add(1)

        go func() { 

            checkFile(filename, orders, ch)

            wg.Done()

        }()

    } 


    go func() { 

        wg.Wait() // after all goroutines are done...

        close(ch) // let range loop below exit

    }()


    for str := range ch { 

        // ...

    } 

}


查看完整回答
反對(duì) 回復(fù) 2022-07-18
?
慕少森

TA貢獻(xiàn)2019條經(jīng)驗(yàn) 獲得超9個(gè)贊

不是答案,而是一些不適合評(píng)論框的評(píng)論。


在這部分代碼中


func main() {

    var (

        ordersFile *os.File

        files       Files

        orders     Orders

        err        error

    )


    mu := new(sync.Mutex)

    wg := &sync.WaitGroup{}

    wg.Add(1)

最后一條語(yǔ)句是對(duì) wg.Add 的調(diào)用,它看起來(lái)是懸空的。我的意思是我們很難理解什么會(huì)觸發(fā)所需的 wg.Done 對(duì)應(yīng)部分。在沒(méi)有 wg.Done 的情況下調(diào)用 wg.Add 是一個(gè)錯(cuò)誤,如果不以這樣的方式編寫(xiě)它們很容易出錯(cuò),我們無(wú)法立即找到它們。


在代碼的那部分,顯然是錯(cuò)誤的


    go func(currentFilename string, ch chan<- map[string][]string, i int, orders Orders, wg *sync.WaitGroup, filenamesSize *int, mu *sync.Mutex, done chan<- bool) {

        wg.Add(1)

        defer wg.Done()

考慮到當(dāng)例程執(zhí)行時(shí),您將 1 添加到等待組,父例程繼續(xù)執(zhí)行??催@個(gè)例子: https: //play.golang.org/p/N9Chaqkv4bd 主程序不等待等待組,因?yàn)樗鼪](méi)有時(shí)間遞增。


還有更多要說(shuō)的,但我發(fā)現(xiàn)很難理解你的代碼的目的,所以我不確定如何在不重寫(xiě)它的情況下進(jìn)一步幫助你。


查看完整回答
反對(duì) 回復(fù) 2022-07-18
  • 3 回答
  • 0 關(guān)注
  • 140 瀏覽
慕課專(zhuān)欄
更多

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢(xún)優(yōu)惠詳情

幫助反饋 APP下載

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

公眾號(hào)

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