MST

星途 面试题库

面试题:Go语言中如何利用goroutine和channel实现并行处理并优化性能

请描述在Go语言中使用goroutine和channel进行并行计算的基本原理,并举例说明如何通过合理分配任务到不同的goroutine,以及使用channel进行数据传递和同步,来提升程序的并行处理性能。假设你要计算1到1000000之间所有能被3整除的数的和,用Go语言代码实现这个并行计算过程。
23.9万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

基本原理

  1. goroutine
    • 在Go语言中,goroutine是一种轻量级的线程,由Go运行时(runtime)管理。与操作系统线程相比,goroutine的创建和销毁开销非常小,可以轻松创建成千上万的goroutine。
    • 当一个函数被作为goroutine启动时,它会与其他goroutine并发执行。例如,go someFunction() 这样的语句会在新的goroutine中启动 someFunction 函数的执行,而不会阻塞当前goroutine的执行。
  2. channel
    • channel是用于在goroutine之间进行通信和同步的管道。它可以是有缓冲的或无缓冲的。
    • 无缓冲的channel要求发送和接收操作同时进行,否则发送或接收操作会阻塞,直到另一方准备好。例如,ch := make(chan int) 创建一个无缓冲的整数类型channel。
    • 有缓冲的channel允许在没有接收方的情况下发送一定数量的数据,缓冲大小在创建时指定,如 ch := make(chan int, 10) 创建一个缓冲大小为10的整数类型channel。
    • 通过channel,goroutine之间可以安全地传递数据,避免了共享内存带来的竞态条件问题。

示例代码

package main

import (
    "fmt"
)

func sumDivisibleBy3(start, end int, resultChan chan int) {
    sum := 0
    for i := start; i <= end; i++ {
        if i%3 == 0 {
            sum += i
        }
    }
    resultChan <- sum
}

func main() {
    const numWorkers = 10
    const totalRange = 1000000
    chunkSize := totalRange / numWorkers
    resultChan := make(chan int, numWorkers)

    for i := 0; i < numWorkers; i++ {
        start := i*chunkSize + 1
        end := (i + 1) * chunkSize
        if i == numWorkers-1 {
            end = totalRange
        }
        go sumDivisibleBy3(start, end, resultChan)
    }

    totalSum := 0
    for i := 0; i < numWorkers; i++ {
        totalSum += <-resultChan
    }
    close(resultChan)

    fmt.Printf("Sum of numbers divisible by 3 from 1 to %d is %d\n", totalRange, totalSum)
}

在上述代码中:

  1. 任务分配
    • 将1到1000000的范围分成10个部分(numWorkers 为10),每个部分的大小为 chunkSize
    • 每个goroutine负责计算一个部分内所有能被3整除的数的和。
  2. 数据传递和同步
    • 使用一个 resultChan 来接收每个goroutine计算的部分和。
    • 主goroutine通过从 resultChan 接收数据,并累加到 totalSum 中,从而得到最终的总和。
    • 当所有goroutine完成计算并将结果发送到 resultChan 后,主goroutine关闭 resultChan 并输出最终结果。