LoginSignup
0
0

More than 5 years have passed since last update.

もう少しスマートにやる方法はないものか

Posted at

idが詰まったsliceがある。(本当はidだけではないが話を簡単にするためにidのみとする)
そのsliceの要素1個1個に「なにかしらの処理」を加えつつ、処理結果を「1つのsliceに詰める」
これをx並列で行う。(とりあえずxの数は4とする)

処理中に起きてほしくないことが起きたときは、

1.最初に起きたエラーの内容を取る
2.すべての処理を即座に止める

2を完全に満たすのはこの要件である限り無理では…?と思いはしたので「ある程度はしょうがない」ものとした。してしまった。くるしい。

package main

import (
    "errors"
    "fmt"
    "math/rand"
    "strconv"
    "sync"
    "time"
)

var ids = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}

func main() {
    rand.Seed(time.Now().UnixNano())
    var wg sync.WaitGroup
    var once sync.Once
    // 並列数制御用
    c := make(chan bool, 4)
    // 失敗検知用
    failC := make(chan struct{})
    // 外部に伝えたい気持ち
    ech := make(chan error, 1)
    mt := &sync.Mutex{}
    result := []string{}

    for _, id := range ids {
        wg.Add(1)
        select {
        case <-failC:
            fmt.Println("fail break")
            break
        default:
            // 渡してやらないとidの重複がでる場合がある...
            go func(id int) {
                c <- true
                fmt.Println("start id:" + strconv.Itoa(id))
                defer func() {
                    <-c
                    wg.Done()
                }()
                select {
                case <-failC:
                    fmt.Println("fail goroutine")
                    return
                default:
                    r := rand.Intn(10)
                    if r == 1 {
                        once.Do(func() {
                            fmt.Println("once id:" + strconv.Itoa(id))
                            ech <- errors.New("ERROR!!")
                            close(failC)
                        })
                        fmt.Println("rand hit id:" + strconv.Itoa(id))
                        return
                    }
                    mt.Lock()
                    result = append(result, "yes_"+strconv.Itoa(id))
                    mt.Unlock()
                }

            }(id)
        }
    }
    wg.Wait()
    if len(ech) > 0 {
        err := <-ech
        fmt.Println(err.Error())
    }
    fmt.Println(result)
    fmt.Println("owari")
}

スマートさ云々の前に、一度も fail break が出力されなかった。
件数が少ないからなのか…?
流石にすべてのgoroutineを生成し終わるまでfuncの中身を処理しない、ってことはあるまい。
うーん。。
errgroupパッケージはgo funcにid渡せなかったんですよね。

    eg.Go(func(id int) error {
        //しょり      
    }(id))

ってやったらid渡せなくて断念。
うーーーーーーん

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0