swdyh

go-enumerable 並行版関数を追加

2013-07-25 18:49:00

Golangでスライスに対してmapやfilter処理をするgo-enumerableに、複数のGoroutineを使って実行するバージョンの関数を追加しました。

func ExampleMakeMapC() {
    var twiceInt func([]int) []int
    f := func(i int) int {
        time.Sleep(10 * time.Millisecond)
        return i * 2
    }
    enumerable.MakeMapC(&twiceInt, f, 2)
    fmt.Println(twiceInt([]int{1, 2, 3}))
    // Output:
    // [2 4 6]
}

MakeMapCではGoroutineの数を指定すると、その数のGoroutineを動かして計算を実行します。この例のようにスリープがあっても、別々のGoroutineで実行されるので逐次実行に比べて速く終わります。

MakeMapCの他にも、FilterとSomeとEvery用のMakeFilterC、MakeSomeC、MakeEveryCがあります。Reduceは前の計算結果に依存するのでありません。

それとMakeFirstというのも追加しました。これはGo Concurrency Patterns http://talks.golang.org/2012/concurrency.slide#48 にでてくるFirstを真似たもので、全部をGroutineで実行して、最初に結果を返した値を返します。複数のサーバにアクセスして最初に帰ってきた値を使うという用途に使えます。

package main

import (
    "fmt"
    "github.com/swdyh/go-enumerable/src/enumerable"
    "io/ioutil"
    "net/http"
)

func main() {
    urls := []string{
        "http://www.google.co.jp",
        "http://www.yahoo.co.jp"}
    var getAll func([]string) []string
    enumerable.MakeMapC(&getAll, func(url string) string {
        res, _ := http.Get(url)
        b, _ := ioutil.ReadAll(res.Body)
        return res.Status + " " + string(b)[0:50]
    }, 2)
    for _, v := range getAll(urls) {
        fmt.Println(v)
    }

    var getFirst func([]string) string
    enumerable.MakeFirst(&getFirst, func(url string) string {
        res, _ := http.Get(url)
        b, _ := ioutil.ReadAll(res.Body)
        return url + " " + res.Status + " " + string(b)[0:50]
    })
    fmt.Println(getFirst(urls))
}

MakeMapCで作ったgetAllは同時にアクセスしてそれぞれの結果を表示します。MakeFirstで作ったgetFirstは最初に返ってきた結果を表示します。

Github https://github.com/swdyh/go-enumerable