Maison > développement back-end > Golang > Tous les goroutines dorment - blocage, sur les canaux tamponnés, je ne comprends pas pourquoi

Tous les goroutines dorment - blocage, sur les canaux tamponnés, je ne comprends pas pourquoi

王林
Libérer: 2024-02-08 20:50:13
avant
926 Les gens l'ont consulté

所有 goroutine 都在睡觉 - 死锁,在缓冲通道上,不明白为什么

Contenu de la question

Je souhaite seulement créer un certain nombre de routines de go, disons 5, mais je peux recevoir un nombre variable de tâches.

Voici le code que j'essaie de faire avec le test en dessous.

package main

import (
    "context"
    "fmt"
    "runtime"
    "time"
)

func dowork(size int, capacity int) int {
    start := time.now()
    jobs := make(chan *job, capacity)
    results := make(chan *job, capacity)
    sem := make(chan struct{}, capacity)
    go chanworker(jobs, results, sem)
    for i := 0; i < size; i++ {
        jobs <- &job{id: i}
    }
    close(jobs)
    successcount := 0
    for i := 0; i < size; i++ {
        item := <-results
        if item.result {
            successcount++
        }
        fmt.printf("job %d completed %v\n", item.id, item.result)
    }
    close(results)
    close(sem)
    fmt.printf("time taken to execute %d jobs with %d capacity = %v\n", size, capacity, time.since(start))
    return successcount
}

func chanworker(jobs <-chan *job, results chan<- *job, sem chan struct{}) {

    for item := range jobs {
        it := item
        sem <- struct{}{}
        fmt.printf("job %d started\n", it.id)
        go func() {
            timeoutctx, cancel := context.withtimeout(context.background(), 300*time.millisecond)
            defer cancel()
            time.sleep(time.duration(it.id) * 100 * time.millisecond)
            select {
            case <-timeoutctx.done():
                fmt.printf("job %d timed out\n", it.id)
                it.result = false
                results <- it
                <-sem
                return
            default:
                fmt.printf("total number of routines %d\n", runtime.numgoroutine())
                it.result = true
                results <- it
                <-sem
            }
        }()
    }
}


Copier après la connexion

Un test à ce sujet

package main

import (
    "testing"
)

func Test_doWork(t *testing.T) {
    type args struct {
        size     int
        capacity int
    }
    tests := []struct {
        name string
        args args
        want int
    }{
        {
            name: "jobs 10 capacity 5",
            args: args{
                size:     10,
                capacity: 5,
            },
            want: 3,
        },
        {
            name: "jobs 100 capacity 5",
            args: args{
                size:     100,
                capacity: 5,
            },
            want: 3,
        },
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            if got := doWork(tt.args.size, tt.args.capacity); got < tt.want {
                t.Errorf("doWork() = %v, want %v", got, tt.want)
            }
        })
    }
}

Copier après la connexion

Test jobs 10 容量 5 有效,但 jobs 100 容量 5 a échoué.

Si je règle la capacité sur 50 pour 100 tâches, cela fonctionne mais pas pour 30 tâches et je ne comprends pas son comportement.

Ce qui suit est ma compréhension de la chaîne et mes attentes quant à son fonctionnement.

Le canal tampon, s'il est plein, se bloquera jusqu'à ce qu'une certaine capacité libre soit disponible. Je m'attendrais à ce qu'une fois le canal d'emplois plein, il se bloque jusqu'à ce que le chanworker en libère certains. Le chanworker lui-même reçoit une capacité et utilise une structure vide pour garantir que pas plus de 5 threads de travail soient créés.

Pourquoi est-ce que j'obtiens l'erreur Erreur fatale : toutes les goroutines dorment - impasse ! ? 致命错误:所有 goroutine 都在休眠 - 死锁!


正确答案


由于主 goroutine 在所有作业都发送到 jobs 之前不会从 results 接收值,因此工作线程会在发送到 results 时阻塞。主 goroutine 阻止发送到 jobs

Réponse correcte

Puisque la goroutine principale ne recevra pas les valeurs des results tant que tous les travaux ne seront pas envoyés aux jobs</code >, Ainsi, le thread de travail se bloque lors de l'envoi à <code>results. La goroutine principale bloque l'envoi vers jobs car le travail est bloqué. Impasse!

Corrigé en utilisant goroutine pour faire le travail.

go func() {
    for i := 0; i < size; i++ {
        jobs <- &Job{id: i}
    }
    close(jobs)
}()
Copier après la connexion
🎜https://www.php.cn/link/6e04df31f1bbb1c02666d0dfa3638f76🎜🎜

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!

source:stackoverflow.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal