Параллельный производитель и потребитель в Go

Я хочу создать производителя/потребителя с программой-менеджером в Go. Например: у меня есть 5 producers, 5 consumers and manager. У производителей есть their own local arrays, они перебирают их и отправляют элементы менеджеру. У потребителей есть their own local arrays с информацией, которую потребляют элементы; они отправляют их также менеджеру. У менеджера это own array, где он хранит какие и сколько элементов есть (например - если производитель отправляет 1 1 2 3 1 2 0 элементов, то массив менеджера выглядит как 1 3 2 1 (один 0, три 1, два 2 и один 3) и он обрабатывает производителей ' и запросы потребителей - помещение элемента в массив (производство) или его удаление (потребление).

Можно ли сделать такую ​​программу на Go? Я уже сделал это в JAVA + CSP с каналами для отправки информации и охранами в менеджере, чтобы определить, какая процедура должна быть выполнена первой, когда производитель и потребитель пытаются обработать один и тот же элемент (например, производитель хочет добавить 1 в массив менеджера и в то же время потребитель хочет потреблять 1).

Любые примеры или советы приветствуются, потому что я не нахожу никакой информации о том, что я хочу сделать. Если нужно, могу дать свой код JAVA+CSP.

ОБНОВЛЕНИЕ. Как насчет синхронизации (чтобы не брать из пустого массива)? Например, если потребитель хочет использовать элемент из массива менеджера, который еще не существует (например, потребитель хочет использовать «3», но у менеджера нет ни одного из них), но у производителя есть этот элемент, и он будет произведен через несколько итерации - как я могу заставить потребителей снова и снова проверять массив менеджеров, пока работа производителей не будет завершена? Должен ли я создавать структуры (или классы) для элементов-потребителей и отмечать, используются они или нет, или в Go есть специальные методы для этого?


person Eddwhis    schedule 23.12.2013    source источник


Ответы (2)


Вот полный пример, включая очистку канала. После того, как все потребители и производители закончены, Менеджер распечатывает результат (для чего я использовал карту, а не срез, так как я думаю, что это немного упрощает код).

package main

import "fmt"

// Consume processes the numbers in ns, sending them on ch after they're
// processed. When the routine is finished, it signals that on done.
func Consume(done chan bool, ch chan int, ns []int) {
    for i := range ns {
        ch <- i
    }
    done <- true
}

// Produce "creates" the numbers in ns, sending them on ch after they're
// produced. When the routine is finished, it signals that on done.
func Produce(done chan bool, ch chan int, ns []int) {
    for i := range ns {
        ch <- i
    }
    done <- true
}

// Manage creates consumers and producers for the given int slices.
// It returns once all consumers and producers are finished.
func Manage(cons, pros [][]int) {
    cch := make(chan int)
    pch := make(chan int)
    dch := make(chan bool)
    n := len(cons) + len(pros)
    data := make(map[int]int)
    for _, c := range cons {
        go Consume(dch, cch, c)
    }
    for _, p := range pros {
        go Produce(dch, pch, p)
    }
    for n > 0 {
        select {
        case c := <-cch:
            data[c] -= 1
        case c := <-pch:
            data[c] += 1
        case <-dch:
            n -= 1
        }
    }
    close(cch)
    close(pch)
    close(dch)
    fmt.Println(data)
}
func main() {
    cons := [][]int{{1, 3, 5}, {0, 1, 5}}
    pros := [][]int{{0, 1, 1}, {3, 5, 5, 7}}
    Manage(cons, pros)
}
person Paul Hankin    schedule 23.12.2013
comment
Просто нужно было изменить эту строку for i := range ns на for _, i := range ns и все работает как положено, спасибо. Но теперь у меня другая проблема, я обновил свой вопрос, если вы можете взглянуть. - person Eddwhis; 24.12.2013

Я сделал пример, очень похожий на то, что вы пытаетесь сделать, проверьте этот суть github

То, как я реализовал это использование одного канала для моего потребителя процесса и другого для моих 2х процессов, которые производят элементы, блок for контролирует передачу от производителей к потребителю, и всякий раз, когда производители ничего не продвигают, цикл будет default. Объекты, перемещаемые по каналам, являются срезами, процессы будут создавать и потреблять заголовки в каждом срезе, отправленном по каналу. Я считаю, что вы можете настроить этот код, чтобы он соответствовал вашему примеру.

person ymg    schedule 23.12.2013
comment
Спасибо за ответ и пример, буду пробовать! - person Eddwhis; 23.12.2013
comment
Удачи, сэр, и не стесняйтесь комментировать здесь, если вам нужна дополнительная помощь. - person ymg; 23.12.2013