Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Semua goroutine sedang tidur - kebuntuan, pada saluran buffer, tidak faham mengapa

Semua goroutine sedang tidur - kebuntuan, pada saluran buffer, tidak faham mengapa

王林
王林ke hadapan
2024-02-08 20:50:13880semak imbas

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

Kandungan soalan

Saya hanya mahu mencipta beberapa rutin pergi, katakan 5, tetapi saya boleh menerima bilangan pekerjaan yang berubah-ubah.

Berikut ialah kod yang saya cuba lakukan ini dengan ujian di bawahnya.

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


Ujian tentang ini

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

Ujian jobs 10 容量 5 有效,但 jobs 100 容量 5 gagal.

Jika saya menetapkan kapasiti 50 untuk 100 kerja ia berfungsi tetapi tidak untuk 30 kerja dan tidak dapat memahami kelakuannya.

Berikut ialah pemahaman saya tentang saluran dan jangkaan saya bahawa ia akan berjaya.

Saluran penimbal, jika penuh, akan disekat sehingga beberapa kapasiti percuma tersedia. Saya menjangkakan bahawa sebaik sahaja saluran kerja penuh ia akan menyekat sehingga pekerja chanworker membebaskan sebahagian daripadanya. Pekerja chanworker itu sendiri menerima kapasiti dan menggunakan struktur kosong untuk memastikan tidak lebih daripada 5 utas pekerja dibuat.

Mengapa saya mendapat ralat Ralat maut: Semua gorouti sedang tidur - kebuntuan! ? 致命错误:所有 goroutine 都在休眠 - 死锁!


正确答案


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

Jawapan betul

Memandangkan goroutine utama tidak akan menerima nilai ​​daripada hasil sehingga semua kerja dihantar ke pekerjaan, Jadi benang pekerja menyekat semasa menghantar ke hasil. Goroutine utama menyekat penghantaran ke jobs kerana kerja itu disekat. kebuntuan!

Dibetulkan dengan menggunakan goroutine untuk melakukan kerja.

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

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

Atas ialah kandungan terperinci Semua goroutine sedang tidur - kebuntuan, pada saluran buffer, tidak faham mengapa. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:stackoverflow.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam