VGrabko
@VGrabko
Golang, Php, Js

Почему после «смерти» воркера сыпятся ошибки?

Погуглив я понял что в го все мои проблеммы решит воркер. Вот что я на говнокодил
package main

import "fmt"
import "sync"

import "time"

var wg sync.WaitGroup

func worker(id int, jobs <-chan int, results chan<- int) {
	defer func() { wg.Done() }()
	for j := range jobs {
		fmt.Println("worker", id, "processing job", j)
		time.Sleep(time.Second)
		results <- j
	}
}

func main() {
	jobs := make(chan int, 100)
	results := make(chan int, 100)

	for w := 1; w <= 10; w++ {
		wg.Add(1)
		go worker(w, jobs, results)
	}

	for j := 1; j <= 90; j++ {
		jobs <- j
	}

	for msg := range results {
		fmt.Println("worker", msg)
	}

	wg.Wait()
	close(jobs)
	close(results)
	fmt.Println("main finished")

}


После завершения кода сыпятся ошибки
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()
        C:/Documents and Settings/lucifer/Рабочий ст
 +0x12d

goroutine 5 [chan receive]:
main.worker(0x1, 0x10744000, 0x107441e0)
        C:/Documents and Settings/lucifer/Рабочий ст
 +0x66
created by main.main
        C:/Documents and Settings/lucifer/Рабочий ст
 +0xc3
  • Вопрос задан
  • 268 просмотров
Решения вопроса 3
fastpars
@fastpars
После for j сделай close(jobs), тогда for range cancel завершится после изъятия последнего элемента из канала
Ответ написан
@qazqazasda
Там же практически по-русски написано: у вас deadlock


У вас тут даже два дидлока

У вас range по каналу result никогда не завершится.
for msg := range results

Вот здесь пример как правильно:
https://gobyexample.com/range-over-channels

К примеру, канал results должен быть закрыт ранее, чем вы входите в
for msg := range results

Но и это еще не все.

Вы никогда не дойдете до close(jobs), потому что у вас стоит wg.Wait(), который завершиться только когда отработают все ваши 10 штук wg.Done()

Но wg.Done() не отработают, как как цикл
for j := range jobs {
завершиться только тогда когда будет вызван close(jobs),

а он будет вызван после всех wg.Done(), а wg.Done() будет вызвано после close(jobs), а close(jobs) ..............
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
kana-desu
@kana-desu
Golang, Clojure, Elixir, Ruby
Работающий пример на play.golang.org

package main

import (
	"fmt"
	"sync"
	"time"
)

var wg sync.WaitGroup

func worker(id int, jobs <-chan int, results chan<- int) {
	defer wg.Done()
	
	for j := range jobs {
		fmt.Println("worker", id, "processing job", j)
		time.Sleep(time.Second)
		results <- j
	}
}

func main() {
	jobs := make(chan int, 100)
	results := make(chan int, 100)

	for w := 1; w <= 5; w++ {
		wg.Add(1)
		go worker(w, jobs, results)
	}

	for j := 1; j <= 10; j++ {
		jobs <- j
	}

	close(jobs)
	wg.Wait()
	close(results)

	for msg := range results {
		fmt.Println("worker", msg)
	}

	fmt.Println("main finished")
}
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы