Всегда тупик с каналами - PullRequest
       11

Всегда тупик с каналами

0 голосов
/ 26 ноября 2018

Я учусь работать с каналами Go и всегда получаю тупики.Что может быть не так с этим кодом?Принтер случайным образом перестает работать, если размеры массивов неравны;Полагаю, это помогло бы как-то уведомить принтер, что приемник перестал работать.Есть идеи как это исправить?Мой код вставлен ниже.

package main

import (
    "fmt"
    "sync"
)

var wg = sync.WaitGroup{}
var wgs = sync.WaitGroup{}
var sg = make(chan int, 50)
var gp1 = make(chan int, 50)
var gp2 = make(chan int, 50)

func main(){
    wgs.Add(2)
    go Sender(0)
    go Sender(11)

    wg.Add(3)
    go Receiver()

    go Printer()
    go Printer2()

    wg.Wait()
}

func Sender(start int){
    defer wgs.Done()
    for i := start; i < 20; i++ {
        sg <- i
    }
}

func Receiver(){
    defer wg.Done()
    for i := 0; i < 20; i++{
        nr := <- sg
        if nr % 2 == 0{
            gp1 <- nr
        } else{
            gp2 <- nr
        }
    }
}

func Printer(){
    defer wg.Done()
    var m [10]int

    for i := 0; i < 10; i++ {
        m[i] = <- gp1
    }

    wgs.Wait()
    fmt.Println(m)
}

func Printer2(){
    defer wg.Done()
    var m [10]int

    for i := 0; i < 10; i++ {
        m[i] = <- gp2
    }

    wgs.Wait()

    fmt.Println(m)
}
// Better to use this one
// func Receiver(senderChannel <-chan int, printerChannel1 chan<- int, printerChannel2 chan<- int, wg *sync.WaitGroup) {

Ответы [ 2 ]

0 голосов
/ 26 ноября 2018

Ваша основная проблема заключается в том, что все в этом «мёртвом расчёте»: они ожидают увидеть фиксированное количество сообщений, но это не обязательно совпадает с реальностью.Вы должны настроить каналы так, чтобы они закрывались после получения всех их данных.

Это, вероятно, означает настройку промежуточной функции для управления отправкой:

func Sender(from, to int, c chan<- int) {
    for i := from; i < to; i++ {
        c <- i
    }
}

func SendEverything(c chan<- int) {
    var wg sync.WaitGroup
    wg.Add(2)
    go func() {
        defer wg.Done()
        Sender(0, 20, c)
    }()
    go func() {
        defer wg.Done()
        Sender(11, 20, c)
    }()
    wg.Wait()
    close(c)
}

Создание диспетчераФункция работает со всем в канале:

func Receive(c <-chan int, odds, evens chan<- int) {
    for n := range c {
        if n%2 == 0 {
            evens <- n
        } else {
            odds <- n
        }
    }
    close(odds)
    close(evens)
}

И затем вы можете поделиться единственной функцией печати:

func Printer(prefix string, c <-chan int) {
    for n := range c {
        fmt.Printf("%s: %d\n", prefix, n)
    }
}

Наконец, у вас есть основная функция, которая объединяет все вместе:

func main() {
    var wg sync.WaitGroup
    inputs := make(chan int)
    odds := make(chan int)
    evens := make(chan int)

    wg.Add(4)
    go func() {
        defer wg.Done()
        SendEverything(inputs)
    }()
    go func() {
        defer wg.Done()
        Receive(inputs, odds, evens)
    }()
    go func() {
        defer wg.Done()
        Printer("odd number", odds)
    }()
    go func() {
        defer wg.Done()
        Printer("even number", evens)
    }()
    wg.Wait()
}

Полный пример приведен по адресу https://play.golang.org/p/qTUqlt-uaWH.

Обратите внимание, что я полностью воздержался от использования каких-либо глобальных переменных, и, как мы надеемся, каждое из них имеет самоочевидное очень короткое имя (i и n - простые целые числа, c - канал) или полные слова (odds, evens).Я обычно держу sync.WaitGroup объекты локально в том месте, где они были созданы.Поскольку все передается как параметры, мне не нужны две копии одной и той же функции для работы с разными глобальными переменными, и если я решу написать тестовый код для этого, я могу создать свои собственные локальные каналы.

0 голосов
/ 26 ноября 2018

Отправитель генерирует (я думаю, 28 сообщений).Примерно половина первых 20 из них идет к одному из gp1 и gp2.Затем принтер и принтер2 выгружают сообщения

Проблема в том, что способ, которым Receiver разбивает сообщения, зависит от того, является ли полученное число нечетным или четным.Но вы не контролируете это.Если в очереди одного из принтеров менее 10 элементов, он зависнет

Это одна потенциальная проблема

...