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
results
empfängt, bis alle Jobs an jobs</code gesendet wurden >, sodass der Arbeitsthread beim Senden an <code>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) }()
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!