Golang中的装配线使用并发

时间:2014-12-08 20:23:16

标签: concurrency go

Go的新手。我正在尝试编写一个“装配线”,其中多个函数像工作者一样工作,并将一些数据结构相互传递,每个函数都对数据结构做了一些事情。

type orderStruct struct {
    orderNum,capacity int
    orderCode uint64
    box [9]int
}


func position0(in chan orderStruct){

    order := <-in

    if((order.orderCode<<63)>>63 == 1){
        order.box[order.capacity] = 1
        order.capacity += 1
    }

    fmt.Println("  filling box {", order.orderNum, order.orderCode, order.box, order.capacity, "} at position 0")
}

func startOrder(in chan orderStruct){

    order := <-in

    fmt.Printf("\nStart an empty box for customer order number %d , request number %d\n", order.orderNum, order.orderCode)
    fmt.Println("  starting box {", order.orderNum, order.orderCode, order.box, order.capacity, "}")

    d := make(chan orderStruct,1)
    go position0(d)
    d <- order
}

func main() {

    var orders [10]orderStruct
    numOrders := len(os.Args)-1
    var x int

    for i := 0; i < numOrders; i++{
        x, _ = strconv.Atoi(os.Args[i+1])
        orders[i].orderCode = uint64(x)
        orders[i].orderNum = i+1
        orders[i].capacity = 0
        for j := 0; j < 9; j++{
            orders[i].box[j] = 0
        }
        c := make(chan orderStruct)
        go startOrder(c)
        c <- orders[i]
    }
}

所以基本上我遇到的问题是startOrder()中的print语句执行正常,但是当我尝试将struct传递给position0()时,没有打印任何内容。我误解了渠道是如何运作的吗?

2 个答案:

答案 0 :(得分:1)

我试图重写您写的内容以正常工作。你可以run it on the playground

主要区别是

  • 只启动了两个例行程序 - 这些作为生产线上的两名工人 - 一个接受订单,另一个接收填充框
  • 使用sync.WaitGroup查看结束时间
  • 使用for x:= range channel
  • 使用close(c)来表示信道结束
  • 您可以启动每个工作人员的多个副本,代码仍然可以正常工作(重复wg.Add(1); go startOrders(c, wg)代码)

这是代码

package main

import (
    "fmt"
    "sync"
)

type orderStruct struct {
    orderNum, capacity int
    orderCode          uint64
    box                [9]int
}

func position0s(in chan orderStruct, wg *sync.WaitGroup) {
    defer wg.Done()
    for order := range in {
        if (order.orderCode<<63)>>63 == 1 {
            order.box[order.capacity] = 1
            order.capacity += 1
        }
        fmt.Println("  filling box {", order.orderNum, order.orderCode, order.box, order.capacity, "} at position 0")
    }
}

func startOrders(in chan orderStruct, wg *sync.WaitGroup) {
    defer wg.Done()
    d := make(chan orderStruct)
    wg.Add(1)
    go position0s(d, wg)

    for order := range in {
        fmt.Printf("\nStart an empty box for customer order number %d , request number %d\n", order.orderNum, order.orderCode)
        fmt.Println("  starting box {", order.orderNum, order.orderCode, order.box, order.capacity, "}")
        d <- order
    }
    close(d)
}

func main() {
    var orders [10]orderStruct
    numOrders := 4
    var x int = 10
    wg := new(sync.WaitGroup)
    c := make(chan orderStruct)
    wg.Add(1)
    go startOrders(c, wg)
    for i := 0; i < numOrders; i++ {
        orders[i].orderCode = uint64(x)
        orders[i].orderNum = i + 1
        orders[i].capacity = 0
        for j := 0; j < 9; j++ {
            orders[i].box[j] = 0
        }
        c <- orders[i]
    }
    close(c)
    wg.Wait()
}

答案 1 :(得分:1)

在Go中学习并发编程时,管道是一个很好的起点。 Nick Craig-Wood的回答为这一具体挑战提供了有效的解决方案。

在Go中有许多其他方法可以使用并发。从广义上讲,根据被视为并发的内容划分了三个类别:

  • 功能分解 - 创建多个功能的管道是一个很好的入门方式 - 这是您的问题的主题。它很容易思考,而且效率很高。但是,如果它进展到真正的并行硬件,那么很难平衡负载。一切都以最慢管道阶段的速度进行。

  • 几何分解 - 将数据划分为可以独立处理(或没有太多通信)的单独区域。基于网格的系统广泛用于科学高性能计算的某些领域,例如天气预报。

  • 农业 - 确定如何将要完成的工作切割成(大量)任务,并将这些任务分配给工人&#39;一个接一个,直到所有的完成。通常,的任务数量超过了工人数量。此类别包括所有所谓的“令人尴尬的并行”。问题(令人尴尬,因为如果你没有让你的高性能系统提供线性加速,你看起来有点愚蠢)。

我可以添加上述几种混合动力车的第四类。

有很多关于此的文献,包括很多来自80年代和90年代奥卡姆编程的时代。 Go和Occam都使用CSP消息传递,因此问题类似。我会挑出有用的书Practical Parallel Processing: An introduction to problem solving in parallel(Chalmers and Tidmus 1996)。