Heim  >  Artikel  >  Backend-Entwicklung  >  Alle Goroutinen schlafen – Deadlock, auf gepufferten Kanälen, ich verstehe nicht warum

Alle Goroutinen schlafen – Deadlock, auf gepufferten Kanälen, ich verstehe nicht warum

王林
王林nach vorne
2024-02-08 20:50:13879Durchsuche

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

Frageninhalt

Ich möchte nur eine bestimmte Anzahl von Go-Routinen erstellen, sagen wir 5, kann aber eine variable Anzahl von Jobs erhalten.

Hier ist der Code, den ich mit dem Test darunter versuche.

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


Ein Test dazu

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 fehlgeschlagen.

Wenn ich die Kapazität für 100 Jobs auf 50 stelle, funktioniert es, aber nicht für 30 Jobs und ich kann sein Verhalten nicht verstehen.

Das Folgende ist mein Verständnis des Kanals und meine Erwartung, dass er funktionieren wird.

Wenn der Pufferkanal voll ist, wird er blockiert, bis freie Kapazität verfügbar wird. Ich gehe davon aus, dass der Jobkanal, sobald er voll ist, blockiert wird, bis der Chanworker einige davon freigibt. Der Chanworker selbst erhält eine Kapazität und sorgt mit einer leeren Struktur dafür, dass nicht mehr als 5 Worker-Threads erstellt werden.

Warum erhalte ich die Fehlermeldung? Schwerwiegender Fehler: Alle Goroutinen schlafen – Deadlock! ? 致命错误:所有 goroutine 都在休眠 - 死锁!


正确答案


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

Richtige Antwort

Da die Hauptgoroutine keine Werte von results empfängt, bis alle Jobs an jobsgesendet wurden >, sodass der Arbeitsthread beim Senden an results blockiert. Die Hauptgoroutine blockiert das Senden an Jobs, weil der Job blockiert ist. Sackgasse!

Behoben durch die Verwendung von Goroutine, um den Job zu erledigen.

go func() {
    for i := 0; i < size; i++ {
        jobs <- &Job{id: i}
    }
    close(jobs)
}()

🎜https://www.php.cn/link/6e04df31f1bbb1c02666d0dfa3638f76🎜🎜

Das obige ist der detaillierte Inhalt vonAlle Goroutinen schlafen – Deadlock, auf gepufferten Kanälen, ich verstehe nicht warum. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen