Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/batch-file/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何实现到goroutines的管道?_Go - Fatal编程技术网

如何实现到goroutines的管道?

如何实现到goroutines的管道?,go,Go,我需要一些帮助来理解如何使用管道来获取从一个goroutine传输到另一个goroutine的数据 我读了这本书,我理解它,但不能完全付诸行动,因此我想寻求社区的帮助 现在,我想出了这个丑陋的代码(): 主程序包 进口( “fmt” “同步” “时间” ) func main(){ wg:=sync.WaitGroup{} ch:=制造(成交量) 对于a:=0;a

我需要一些帮助来理解如何使用管道来获取从一个goroutine传输到另一个goroutine的数据

我读了这本书,我理解它,但不能完全付诸行动,因此我想寻求社区的帮助

现在,我想出了这个丑陋的代码():

主程序包
进口(
“fmt”
“同步”
“时间”
)
func main(){
wg:=sync.WaitGroup{}
ch:=制造(成交量)
对于a:=0;a<3;a++{
工作组.添加(1)
go func1(内部(3-a)、通道和工作组)
}
go func(){
wg.Wait()
关闭(ch)
}()
wg2:=sync.WaitGroup{}
ch2:=制造(成串)
对于val:=范围ch{
fmt.Println(val)
wg2.添加(1)
go func2(val、ch2和wg2)
}
go func(){
wg2.Wait()
关闭(ch2)
}()
对于val:=范围ch2{
fmt.Println(val)
}
}

func func1(seconds int,ch chan这篇文章的关键模式是,您可以将通道的内容视为数据流,并编写一组协作的goroutine来构建数据处理流图。这是一种在面向数据的应用程序中获得某种并发性的方法

在设计方面,您可能会发现构建与goroutine结构无关的块并将它们封装在通道中更有帮助。这使得测试较低级别的代码更加容易,如果您改变主意是否在goroutine中运行,则添加或删除包装器就更容易了

因此,在您的示例中,我首先将最低级别的任务重构为它们自己的(同步)函数:

func fetch(ms int) int {
    time.Sleep(time.Duration(ms) * time.Millisecond)
    return ms
}

func report(ms int) string {
    return fmt.Sprintf("Hello after %d ms", ms)
}
由于示例的后半部分是相当同步的,因此很容易适应管道模式。我们编写了一个函数,该函数使用它的所有输入流并生成完整的输出流,完成后关闭它

func reportAll(mss <-chan int, out chan<- string) {
    for ms := range mss {
        out <- report(ms)
    }
    close(out)
}
这是一个完整的例子

我避免了在这里手动传递
sync.WaitGroup
s(一般来说,你不会有一个WaitGroup,除非你明确地将某个东西作为goroutine的顶层调用,因此将WaitGroup管理推到调用方会使代码更加模块化;请参见上面的my
fetchAll
函数以获取示例).我如何知道我所有的Goroutine都已完成?我们可以通过以下方式跟踪:

  • 如果我已到达
    main
    的末尾,则
    results
    频道将关闭
  • results
    通道是
    reportAll
    的输出通道;如果关闭,则该函数到达其执行结束;如果发生这种情况,则关闭
    获取的
    通道
  • fetched
    通道是
    fetchAll
    的输出通道
另一种方式是,一旦管道的源(
produceInputs
)关闭其输出通道并完成,“我完成了”信号沿着管道向下流动,并导致下游步骤关闭其输出通道并完成

这篇博文提到了一个单独的显式关闭通道。我在这里根本没有讨论过这个问题。但是,自从它被编写以来,标准库获得了这个包,这现在是管理这些通道的标准习惯用法。您需要在主循环体中使用
select
语句,这使得处理更加复杂复杂。这可能看起来像:

func reportAllCtx(ctx context.Context, mss <-chan int, out chan<- string) {
    for {
        select {
            case <-ctx.Done():
                break
            case ms, ok := <-mss:
                if ok {
                    out <- report(ms)
                } else {
                    break
                }
            }
        }
    }
    close(out)
}

func reportAllCtx(ctx context.context,mss这篇文章的关键模式是,您可以将通道的内容视为数据流,并编写一组协作的goroutine来构建数据处理流图。这是一种在面向数据的应用程序中获得某种并发性的方法

在设计方面,您可能会发现构建与goroutine结构无关的块并将它们封装在通道中更有帮助。这使得测试较低级别的代码更加容易,如果您改变主意是否在goroutine中运行,则添加或删除包装器就更容易了

因此,在您的示例中,我首先将最低级别的任务重构为它们自己的(同步)函数:

func fetch(ms int) int {
    time.Sleep(time.Duration(ms) * time.Millisecond)
    return ms
}

func report(ms int) string {
    return fmt.Sprintf("Hello after %d ms", ms)
}
由于示例的后半部分是相当同步的,因此很容易适应管道模式。我们编写了一个函数,该函数使用它的所有输入流并生成完整的输出流,完成后关闭它

func reportAll(mss <-chan int, out chan<- string) {
    for ms := range mss {
        out <- report(ms)
    }
    close(out)
}
这是一个完整的例子

我避免了在这里手动传递
sync.WaitGroup
s(一般来说,你不会有一个WaitGroup,除非你明确地将某个东西作为goroutine的顶层调用,因此将WaitGroup管理推到调用方会使代码更加模块化;请参见上面的my
fetchAll
函数以获取示例).我如何知道我所有的Goroutine都已完成?我们可以通过以下方式跟踪:

  • 如果我已到达
    main
    的末尾,则
    results
    频道将关闭
  • results
    通道是
    reportAll
    的输出通道;如果关闭,则该函数到达其执行结束;如果发生这种情况,则关闭
    获取的
    通道
  • fetched
    通道是
    fetchAll
    的输出通道
另一种方式是,一旦管道的源(
produceInputs
)关闭其输出通道并完成,“我完成了”信号沿着管道向下流动,并导致下游步骤关闭其输出通道并完成

这篇博文提到了一个单独的显式关闭通道。我在这里根本没有讨论过这个问题。但是,自从它被编写以来,标准库获得了这个包,这现在是管理这些通道的标准习惯用法。您需要在主循环体中使用
select
语句,这使得处理更加复杂复杂。这可能看起来像:

func reportAllCtx(ctx context.Context, mss <-chan int, out chan<- string) {
    for {
        select {
            case <-ctx.Done():
                break
            case ms, ok := <-mss:
                if ok {
                    out <- report(ms)
                } else {
                    break
                }
            }
        }
    }
    close(out)
}
func reportAllCtx(ctx context.Context, mss <-chan int, out chan<- string) {
    for {
        select {
            case <-ctx.Done():
                break
            case ms, ok := <-mss:
                if ok {
                    out <- report(ms)
                } else {
                    break
                }
            }
        }
    }
    close(out)
}