【问题标题】:A problem occurred during the parallel computing in matrix in golanggolang中矩阵并行计算出现问题
【发布时间】:2021-12-25 05:33:02
【问题描述】:

当我尝试在我的玩具示例中为矩阵的每个元素添加一个固定值时,我遇到了一个错误。我的想法是将整个矩阵分成几个子矩阵,并在并行计算期间使用映射来保存起始索引和子矩阵。我已经完成了之前的要求。但是当我想更进一步时,我想让我的边界相互交互,同时不丢失任何有用的信息,就像元胞自动机游戏一样,它们的位置将由一些邻居决定。因此,我并没有将整个矩阵分割成完美的方式,而是特意添加了一些冗余行,让边界获得正确的值,如下面的方式,在最后的组合部分,我可以简单地留下那些不正确的边界并保留正确的计算体。

假设我们有 3 个 CPU,输入矩阵是 10 x 10 矩阵。因此,我将创建三个围棋例程。如前所述,我允许一些房间来处理边界情况。因此,我在分割过程中在不同子板之间留出了一些空间或重叠。为了达到目的,我手动在子板前加一行,在子板后加一行,也就是说我要写三个if语句,第一种情况是子板以0开头,我们只能添加下一个子板的一排。第二种情况是中间的情况,在顶部之前添加一排,从下方添加一排底部。最后一种情况是不要从下面添加另一行。但是,当我尝试并行运行代码时,似乎在 goroutine 期间发生了一些污染,我不知道这是怎么发生的。假设 goroutine 之前的输入子板和 go-routine 中的子板应该是相同的,尽管顺序可能不同。在这种情况下,goroutine 函数中的值可能会被污染。我不知道为什么会发生这种情况。由于打印方法和断点方法在并行编程中可能不起作用。我真的很困惑,不知道在这种情况下发生了什么。我还附上了下面的代码,如果你想复制它。


func TestParallelMatrixMapInteraction(t *testing.T) {
    wg := sync.WaitGroup{}
    boards := GenerateMatrix(10)
    //for i := 0; i < len(boards); i++ {
    // fmt.Println(boards[i])
    //}
    numProcess := 3
    nRows := len(boards)

    subRows := nRows / numProcess
    sumRow := func(subBoard [][]int, c chan map[int][][]int, startIdx int) {
        // input
        fmt.Println("The input of subBoard in goroutine: ", subBoard, "with start idx ",startIdx)
        defer wg.Done()
        for i := 0; i < len(subBoard); i++ {
            for j := 0; j < len(subBoard[i]); j++ {
                subBoard[i][j] += 4
                //fmt.Println(subBoard[i][j])
            }
        }
        subBoardMap := make(map[int][][]int)
        subBoardMap[startIdx] = subBoard
        //fmt.Println("After the modification, the subBoard is:", subBoardMap)
        c <- subBoardMap
    }

    c := make(chan map[int][][]int)
    //c := make(chan map[int][][]int, subRows)

    // iterate through all the available number of process
    for i := 0; i < numProcess; i++ {
        // split into numProcess approx . equal pieces
        startIdx := i * subRows
        endIdx := (i + 1) * subRows
        if startIdx ==0  {
            wg.Add(1)
            subBoard := boards[startIdx : endIdx+1]
            fmt.Println("The input of subBoard: ", subBoard, "with start idx ",startIdx)
            go sumRow(subBoard, c, startIdx)
        } else if i < numProcess-1 {
            wg.Add(1)
            subBoard := boards[startIdx-1 : endIdx+1]
            fmt.Println("The input of subBoard: ", subBoard, "with start idx ",startIdx-1)
            go sumRow(subBoard, c, startIdx-1)
        } else { // i = numProcess -1
            wg.Add(1)
            subBoard := boards[startIdx-1:]
            fmt.Println("The input of subBoard: ", subBoard, "with start idx ",startIdx-1)
            go sumRow(subBoard, c, startIdx-1)
        }
    }

    newBoard := GenerateEmptyMatrix(10)

    for i := 0; i < numProcess; i++ {
        subBoardMap := <-c
        //fmt.Println("=====================================")
        //fmt.Println("The output from channel: It would be a map",subBoardMap)
        var startIdx int
        var subBoard [][]int
        for idx, value := range subBoardMap {
            startIdx = idx
            subBoard = value
        }
        endIdx := startIdx + len(subBoard)

        var actualStart int
        var actualEnd int
        if startIdx == 0 {
            actualStart = startIdx
            actualEnd = actualEnd - 1
        } else if endIdx == len(newBoard) {
            actualStart = startIdx + 1
            actualEnd = endIdx
        } else {
            actualStart = startIdx + 1
            actualEnd = endIdx - 1
        }

        for j := actualStart; j < actualEnd; j++ {
            newBoard[j] = subBoard[j-actualStart]
        }
    }
    wg.Wait()

    fmt.Println("=================ready to draw the matrix====================")

    for i := 0; i < len(newBoard); i++ {
        fmt.Println(newBoard[i])
    }

}

func GenerateMatrix(size int) [][]int {
    board := make([][]int, size)
    for i := 0; i < size; i++ {
        board[i] = make([]int, size)
    }

    for i := 0; i < len(board); i++ {
        for j := 0; j < len(board[0]); j++ {
            board[i][j] = i
        }
    }
    return board
}

func GenerateEmptyMatrix(size int) [][]int {
    board := make([][]int, size)
    for i := 0; i < size; i++ {
        board[i] = make([]int, size)
    }
    return board
}

我还附上了前面提到的正确运行的矩阵示例,我真的很好奇导致这种差异的原因以及我的错误到底在哪里。

func TestParallelMatrixMap(t *testing.T) {
    wg := sync.WaitGroup{}
    boards := GenerateMatrix(20)
    for i := 0; i < len(boards); i++ {
        fmt.Println(boards[i])
    }
    numProcess := 3
    nRows := len(boards)

    subRows := nRows / numProcess
    sumRow := func(subBoard [][]int, c chan map[int][][]int, startIdx int) {
        fmt.Println("The input of subBoard in goroutine: ", subBoard, "with start idx ",startIdx)
        defer wg.Done()
        for i := 0; i < len(subBoard); i++ {
            for j := 0; j < len(subBoard[0]); j++ {
                subBoard[i][j] += 4
            }
        }
        subBoardMap := make(map[int][][]int)
        subBoardMap[startIdx] = subBoard
        c <- subBoardMap
    }

    c := make(chan map[int][][]int, subRows)

    // iterate through all the available number of process
    for i := 0; i < numProcess; i++ {
        // split into numProcess approx . equal pieces
        startIdx := i * subRows
        endIdx := (i + 1) * subRows
        if i < numProcess-1 {
            wg.Add(1)
            go sumRow(boards[startIdx:endIdx], c, startIdx)
        } else { // i = numProcess -1
            wg.Add(1)
            go sumRow(boards[startIdx:], c, startIdx)
        }
    }

    newBoard := GenerateEmptyMatrix(20)

    for i := 0; i < numProcess; i++ {
        subBoardMap := <-c
        var startIdx int
        var subBoard [][]int
        for idx, value := range subBoardMap {
            startIdx = idx
            subBoard = value
        }
        endIdx := startIdx + len(subBoard)

        for j := startIdx; j < endIdx; j++ {
            newBoard[j] = subBoard[j-startIdx]
        }
    }
    wg.Wait()

    fmt.Println("=================ready to draw the matrix====================")

    for i := 0; i < len(newBoard); i++ {
        fmt.Println(newBoard[i])
    }

}

【问题讨论】:

    标签: channel parallels


    【解决方案1】:

    我自己找到了答案,一般是golang切片中的浅拷贝和深拷贝问题。因为我使用 [startIdx-1:endIdx+1] 方法添加了相邻的两行,由于 goroutine 并行计算的内在本质是无序的,所以之前的行可能已经被修改了,这说明我的输出会出现这样的情况乱七八糟,没有秩序。

    为避免此问题,您可以创建一个复制函数,该函数创建一个新切片并遍历旧切片并将值分配给新切片。只有这样,我们得到的切片才是深拷贝,并且独立于其他修改。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-09
      • 2020-11-08
      • 1970-01-01
      • 1970-01-01
      • 2017-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多