在golang中,如何编写一个为下一阶段引入延迟的管道阶段?

时间:2017-10-20 18:08:04

标签: asynchronous go concurrency channel goroutine

我正在关注https://blog.golang.org/pipelines文章,以实施几个阶段。

我需要其中一个阶段在事件传递到管道中的下一个阶段之前引入几秒的延迟。

我对下面代码的关注是它会在传递事件之前产生无限数量的go例程time.Sleep()。有更好的方法吗?

谢谢!

func fooStage(inChan <- chan *Bar) (<- chan *Bar) {
    out := make(chan *Bar, 10000)
    go func() {
        defer close(out)
        wg := sync.WaitGroup{}
        for {
            select {
            case event, ok := <-inChan:
                if !ok {
                    // inChan closed
                    break
                }
                wg.Add(1)
                go func() {
                    time.Sleep(5 * time.Second)
                    out <- event
                    wg.Done()
                }()
            }
        }
        wg.Wait()
    }()
    return out
}

5 个答案:

答案 0 :(得分:1)

您可以使用其他通道来限制循环能够创建的活动goroutine的数量。

const numRoutines = 10

func fooStage(inChan <-chan *Bar) <-chan *Bar {
    out := make(chan *Bar, 10000)
    routines := make(chan struct{}, numRoutines)
    go func() {
        defer close(out)
        wg := sync.WaitGroup{}
        for {
            select {
            case event, ok := <-inChan:
                if !ok {
                    // inChan closed
                    break
                }
                wg.Add(1)
                routines <- struct{}{}
                go func() {
                    time.Sleep(5 * time.Second)
                    out <- event
                    wg.Done()
                    <-routines
                }()
            }
        }
        wg.Wait()
    }()
    return out
}

答案 1 :(得分:1)

您可以手动修复goroutines的数量 - 仅从您需要的数字开始。

func sleepStage(in <-chan *Bar) (out <-chan *Bar) {
     out = make(<-chan *Bar)
     wg := sync.WaitGroup
     for i:=0; i < N; i++ {  // Number of goroutines in parallel
           wg.Add(1)
           go func(){
                defer wg.Done()
                for e := range in {
                    time.Sleep(5*time.Seconds)
                    out <- e
                }
            }()
      }
      go func(){}
           wg.Wait()
           close(out)
       }()
       return out
  }

答案 2 :(得分:0)

您可以使用std::string line; while (getline(ss, line) && !line.empty()) { size_t startOfNumbers = line.find_first_of("0123456789"); size_t endOfName = line.find_last_not_of(" ", startOfNumbers); std::string name = line.substr(0, endOfName); // Extract name std::stringstream nums(line.substr(startOfNumbers)); // Get rest of the line int num1, num2; nums >> num1 >> num2; // Read numbers std::cout << name << " " << num1 << " " << num2 << std::endl; }

time.Ticker

答案 3 :(得分:0)

这是您应该用于管道应用程序的内容。上下文允许更快地拆除。

负责管理您的 in 频道的必须在拆除期间关闭它。 始终关闭您的频道。

// Delay delays each `interface{}` coming in through `in` by `duration`.
// If the context is canceled, `in` will be flushed until it closes.
// Delay is very useful for throtteling back CPU usage in your pipelines.
func Delay(ctx context.Context, duration time.Duration, in <-chan interface{}) <-chan interface{} {
    out := make(chan interface{})
    go func() {
        // Correct memory management
        defer close(out)

        // Keep reading from in until its closed
        for i := range in {
            // Take one element from in and pass it to out
            out <- i

            select {
            // Wait duration before reading from in again
            case <-time.After(duration):

            // Don't wait if the context is canceled
            case <-ctx.Done():
            }
        }
    }()
    return out
}

答案 4 :(得分:0)

我已经用我的 pipeline library 解决了这样的问题,就像这样:

    import "github.com/nazar256/parapipe"
    //...
    pipeline := parapipe.NewPipeline(10).
    Pipe(func(msg interface{}) interface{} {
        //some code
    }).
    Pipe(func(msg interface{}) interface{} {
        time.Sleep(3*time.Second)
        return msg
    }).
    Pipe(func(msg interface{}) interface{} {
        //some other code
    })