Maison  >  Article  >  développement back-end  >  Impasse en attendant le tuyau io.Copie dans Goroutine

Impasse en attendant le tuyau io.Copie dans Goroutine

PHPz
PHPzavant
2024-02-15 15:10:08510parcourir

在 Goroutine 中等待管道 io.Copy 时发生死锁

L'impasse lors de l'attente du pipeline io.La copie dans Goroutine est un problème courant. Lorsque nous attendons la fin de io.Copy dans un Goroutine, si le tube n'est pas correctement fermé, cela provoquera un blocage. Dans ce cas, Goroutine continuera d'attendre les données et ne pourra pas poursuivre l'exécution. La solution à ce problème consiste à fermer manuellement le tube une fois l'exécution de io.Copy terminée pour garantir que la Goroutine puisse se terminer correctement. L'éditeur PHP Apple a présenté en détail les causes et les solutions à ce problème, dans l'espoir de vous aider à mieux gérer ce type de situation de blocage.

Contenu de la question

Dans le code ci-dessous, la fonction pour io.copy 的调用永远不会返回;它只是无限期地阻塞,导致死锁。仅当使用 io.pipeio.reader 连接到 os.stdout io.writer 时,才会发生此行为。但是,我需要使用管道,因为在我的完整代码中,我使用 io.multiwriterio.pipes 将一个 io.reader 连接到许多需要 io.reader.

func main() {
    read := strings.newreader("abcdefghij")
    pipereader, pipewriter := io.pipe()

    var wg sync.waitgroup
    wg.add(1)
    go func() {
        println("start copy")
        _, err := io.copy(os.stdout, pipereader)
        if err != nil {
            println(err.error())
        }
        println("end copy")
        wg.done()
    }()

    _, err := io.copy(pipewriter, read)
    if err != nil {
        println(err.error())
    }

    wg.wait()
}

Sortie :

Start copy
abcdefghij
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc0000b0018?)
    /usr/local/go-faketime/src/runtime/sema.go:62 +0x25
sync.(*WaitGroup).Wait(0x4969c8?)
    /usr/local/go-faketime/src/sync/waitgroup.go:139 +0x52
main.main()
    /tmp/sandbox4108076976/prog.go:31 +0x23c

goroutine 18 [select]:
io.(*pipe).read(0xc0000a6120, {0xc0000b6000, 0x8000, 0xc00009e101?})
    /usr/local/go-faketime/src/io/pipe.go:57 +0xb1
io.(*PipeReader).Read(0x10?, {0xc0000b6000?, 0xc00009e1e0?, 0x4f75a0?})
    /usr/local/go-faketime/src/io/pipe.go:136 +0x25
io.copyBuffer({0x496aa8, 0xc00009e1e0}, {0x4969a8, 0xc0000a4018}, {0x0, 0x0, 0x0})
    /usr/local/go-faketime/src/io/io.go:427 +0x1b2
io.Copy(...)
    /usr/local/go-faketime/src/io/io.go:386
os.genericReadFrom(0xb000000006018ab?, {0x4969a8, 0xc0000a4018})
    /usr/local/go-faketime/src/os/file.go:162 +0x67
os.(*File).ReadFrom(0xc0000a4008, {0x4969a8, 0xc0000a4018})
    /usr/local/go-faketime/src/os/file.go:156 +0x1b0
io.copyBuffer({0x496a28, 0xc0000a4008}, {0x4969a8, 0xc0000a4018}, {0x0, 0x0, 0x0})
    /usr/local/go-faketime/src/io/io.go:413 +0x14b
io.Copy(...)
    /usr/local/go-faketime/src/io/io.go:386
main.main.func1()
    /tmp/sandbox4108076976/prog.go:18 +0x71
created by main.main
    /tmp/sandbox4108076976/prog.go:16 +0x1d3

Voici le lien du terrain de jeu vers le code : https://goplay.tools/snippet/70ubgiz8ftv

Existe-t-il un moyen d'éviter les impasses tout en préservant io.pipe ?

Solution de contournement

Fermez l'extrémité d'écriture du tuyau lorsque vous avez terminé :

_, err := io.Copy(pipeWriter, read)
pipeWriter.Close()
if err != nil {
    println(err.Error())
}

Sinon, le lecteur attendra indéfiniment.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer