Maison  >  Article  >  développement back-end  >  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

王林
王林avant
2024-02-08 20:50:13880parcourir

所有 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
            }
        }()
    }
}


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)
            }
        })
    }
}

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, Ainsi, le thread de travail se bloque lors de l'envoi à 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)
}()

🎜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!

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