Минутка рекламы. Вот решение задачи на Go. Оно длинное, потому что я его
обильно снабдил комментариями. Если лишнее убрать, всё будет выглядеть
очень компактно и работать производительно.


package main
import (
        "fmt"
        "math/rand"
        "time"
)
const (
        numWorkers = 10
)
// task - это задание для воркера.type task struct {
        value  int
        output chan result
}
// result - это результат обработки задания воркером.type result struct {
        value  int
        worker int
}
// worker берёт данные из канала input, обрабатывает их (умножает на
100) и кладёт в канал ответа,// который прислан вместе с заданием.func
worker(workerNumber int, input chan task) {
        // Пока входной канал не закроют, читаем из него задание.
        for task := range input {
                // Работаем в поте лица.
                time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
                task.output <- result{task.value * 100, workerNumber}
        }
}
// prepareInput готовит входные задания и кладёт их в два канала: в
одну очередь// задания для воркеров, в другую - каналы ответа.func
prepareInput(input chan task, output chan chan result) {
        for i := 0; i < 100; i++ {
                // Канал ответа буферизованный, чтобы воркер не ждал, когда его 
ответ считают,
                // а сразу брался за следующее задание.
                outputChan := make(chan result, 1)
                // Тот факт, что задания кладутся в input и output в одном и 
том же порядке,
                // гарантирует, что ответы будут упорядочены в том же порядке.
                input <- task{i, outputChan}
                output <- outputChan
        }
        close(input)
        close(output)
}
func main() {
        // Каналы обязательно буферизованные (длина буфера = числу воркеров).
        input := make(chan task, numWorkers)
        output := make(chan chan result, numWorkers)

        // Запускаем готовилку входных данных.
        go prepareInput(input, output)

        // Запускаем воркеры.
        for i := 0; i < numWorkers; i++ {
                go worker(i, input)
        }

        // Читаем ответы в порядке, в каком нам нужно.
        for res := range output {
                fmt.Printf("%+v\n", <-res)
        }
}



5 июня 2014 г., 13:46 пользователь Харпалёв Иван <[email protected]>
написал:

> Добрый день, могучий MoscowPM
>
> Опять про параллельную обработку.
>
> Хочется написать вот такую схему обработки ввода:
> master создаёт work'ов,
> читает порции из файла, раздаёт порции worker'ам
> ждёт, пока worker обработает, получает ответ worker'a
> пишет результат в файл.
> Так же мастер буфереизует вывод, чтобы выход писался в правильном порядке.
>
> Самое туманное:
> Как передавать данные от мастера к worker'у и Обратно?!!!!
> Как ждать готовности?!!!
> Должна ли такая схема (работа с диском из одного места) дать ускорение по
> сравнению с чтением/записью файла в каждом worker'е?
>
> смотрел на Coro, увидел Coro::Simaphore, Coro::Signal ... но не пойму:
>   как сделать разделяемую память, (как быстро передавать данные между
> мастером и worker'ом внутри Perl)?
>   как сделать неблокирующее ожидание готовности одного из worker'ов (при
> котором можно заниматься вводом-выводом)?
>
> Подскажите, на чём и как такое писать!!
> Спасибо!
>
> Уважение
> Иван Харпалев
>
>
>
> --
> Moscow.pm mailing list
> [email protected] | http://moscow.pm.org
>
>
-- 
Moscow.pm mailing list
[email protected] | http://moscow.pm.org

Ответить