2015-01-07 3 views
1

Как создать срез каналов и функцию запуска double(i) одновременно внутри кусочка итерации:ломтика каналов и одновременно функция выполнение

package main 

import (
    "fmt" 
    "time" 
) 

func double(i int) int { 
    result := 2 * i 
    fmt.Println(result) 
    time.Sleep(500000000) 
    return result 
} 

func notParallel(arr []int) (outArr []int) { 
    for _, i := range arr { 
     outArr = append(outArr, double(i)) 
    } 
    return 
} 

// how to do the same as notParallel func in parallel way. 
// For each element of array double func should evaluate concuruntly 
// without waiting each next element to eval 
func parallel(arr []int) (outArr []int) { 

    var chans []chan int 
    for i := 0; i < len(arr); i++ { 
     chans[i] = make(chan int) // i = 0 : panic: runtime error: index out of range 
    } 

    for counter, number := range arr { 
     go func() { 
      chans[counter] <- double(number) 
     }() 
    } 

    return 
} 

func main() { 
    arr := []int{7, 8, 9} 
    fmt.Printf("%d\n", notParallel(arr)) 
    fmt.Printf("%d\n", parallel(arr)) 
} 

playground

В функции double(i) спит в течение 500 мса функционирует notParallel(arr []int) работы на 1500 мс для 3 элементов arr []int, но функция parallel(arr []int) будет работать около 500 мс.

В моей реализации есть ошибка ...

panic: runtime error: index out of range 

... на линии ...

chans[i] = make(chan int) // i = 0 
+2

Ответ на этот вопрос велик, но, отвечая на ваш конкретный вопрос, 'var chans [] chan int' только объявляет' chans', но вам также нужно выделить его. Это можно сделать в одном выражении с помощью команды chans: = make ([] chan int, len (arr)). Это не относится к 'chan', но обычно для срезов любого типа. – siritinga

+1

Side nit: не делайте 'time.Sleep (500000000)', вместо этого выполняйте 'time.Sleep (500 * time.Millisecond)'. –

+1

Еще один нит: [ломтики и массивы очень разные в Go] (https://blog.golang.org/slices), вы повторяли ссылку на срез как массив, который, как минимум, является ошибкой в ​​комментариях, но может также быть признак серьезного недоразумения. –

ответ

2

В этом случае вам не нужно использовать чан.

package main 

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

func double(i int) int { 
    result := 2 * i 
    fmt.Println(result) 
    time.Sleep(500000000) 
    return result 
} 

func notParallel(arr []int) (outArr []int) { 
    for _, i := range arr { 
     outArr = append(outArr, double(i)) 
    } 
    return 
} 

// how to do the same as notParallel func in parallel way. 
// For each element of array double func should evaluate concuruntly 
// without waiting each next element to eval 
func parallel(arr []int) (outArr []int) { 
    outArr = make([]int, len(arr)) 
    var wg sync.WaitGroup 
    for counter, number := range arr { 
     wg.Add(1) 
     go func(counter int, number int) { 
      outArr[counter] = double(number) 
      wg.Done() 
     }(counter, number) 
    } 
    wg.Wait() 

    return 
} 

func main() { 
    arr := []int{7, 8, 9} 
    fmt.Printf("%d\n", notParallel(arr)) 
    fmt.Printf("%d\n", parallel(arr)) 
} 

Потому что параллель должна дождаться окончания отделки гортани (ов).

И я замечаю, что ваш код не работает, потому что вы ссылаетесь counter, number в той же области действия.

+1

Незначительный комментарий для тех, кто может не знать об этом: когда вы знаете заранее, сколько раз будет вызываться 'wg.Add (1)', это может быть полезно просто сделать wg.Add (len (arr)) 'один раз перед циклом. Для всех вызовов группы ожидания требуется синхронизация, поэтому может быть полезно минимизировать такие вызовы. Конечно, если вы считаете, что это более четкое или более читаемое (или если вы не знаете общее количество времени раньше), то вызов 'wg.Add (1)' тоже отлично. –

 Смежные вопросы

  • Нет связанных вопросов^_^