> 백엔드 개발 > Golang > 목록을 개별 고루틴에 의해 처리되는 더 작은 덩어리로 분할했음에도 불구하고 'moving_avg_concurrent2'의 성능이 동시성이 향상되지 않는 이유는 무엇입니까?

목록을 개별 고루틴에 의해 처리되는 더 작은 덩어리로 분할했음에도 불구하고 'moving_avg_concurrent2'의 성능이 동시성이 향상되지 않는 이유는 무엇입니까?

Linda Hamilton
풀어 주다: 2024-12-23 16:38:13
원래의
178명이 탐색했습니다.

Why is the performance of `moving_avg_concurrent2` not improving with increased concurrency, despite splitting the list into smaller chunks processed by individual goroutines?

동시 실행이 증가해도 Moving_avg_concurrent2의 성능이 향상되지 않는 이유는 무엇입니까?

moving_avg_concurrent2는 목록을 더 작은 조각으로 나누고 단일 고루틴을 사용하여 각 조각을 처리합니다. 어떤 이유로(이유는 명확하지 않음) 하나의 고루틴을 사용하는 이 함수는 Moving_avg_serial4보다 빠르지만 여러 고루틴을 사용하면 Moving_avg_serial4보다 성능이 떨어지기 시작합니다.

moving_avg_concurrent3이 Moving_avg_serial4보다 훨씬 느린 이유는 무엇입니까?

고루틴을 사용할 때 Moving_avg_concurrent3의 성능은 Moving_avg_serial4보다 나쁩니다. num_goroutines를 늘리면 성능이 향상될 수 있지만, Moving_avg_serial4보다 여전히 나쁩니다.

고루틴은 가볍지만 완전 무료는 아니지만, 발생하는 오버헤드가 너무 커서 Moving_avg_serial4보다 느린 것이 가능합니까?

예, 고루틴은 가볍지만 무료는 아닙니다. 여러 고루틴을 사용하는 경우 고루틴을 시작하고 관리하고 예약하는 데 드는 오버헤드가 병렬 처리 증가로 인한 이점보다 클 수 있습니다.

코드

기능:

// 返回包含输入移动平均值的列表(已提供,即未优化)
func moving_avg_serial(input []float64, window_size int) []float64 {
    first_time := true
    var output = make([]float64, len(input))
    if len(input) > 0 {
        var buffer = make([]float64, window_size)
        // 初始化缓冲区为 NaN
        for i := range buffer {
            buffer[i] = math.NaN()
        }
        for i, val := range input {
            old_val := buffer[int((math.Mod(float64(i), float64(window_size))))]
            buffer[int((math.Mod(float64(i), float64(window_size))))] = val
            if !NaN_in_slice(buffer) && first_time {
                sum := 0.0
                for _, entry := range buffer {
                    sum += entry
                }
                output[i] = sum / float64(window_size)
                first_time = false
            } else if i > 0 && !math.IsNaN(output[i-1]) && !NaN_in_slice(buffer) {
                output[i] = output[i-1] + (val-old_val)/float64(window_size) // 无循环的解决方案
            } else {
                output[i] = math.NaN()
            }
        }
    } else { // 空输入
        fmt.Println("moving_avg is panicking!")
        panic(fmt.Sprintf("%v", input))
    }
    return output
}

// 返回包含输入移动平均值的列表
// 重新排列控制结构以利用短路求值
func moving_avg_serial4(input []float64, window_size int) []float64 {
    first_time := true
    var output = make([]float64, len(input))
    if len(input) > 0 {
        var buffer = make([]float64, window_size)
        // 初始化缓冲区为 NaN
        for i := range buffer {
            buffer[i] = math.NaN()
        }
        for i := range input {
            //            fmt.Printf("in mvg_avg4: i=%v\n", i)
            old_val := buffer[int((math.Mod(float64(i), float64(window_size))))]
            buffer[int((math.Mod(float64(i), float64(window_size))))] = input[i]
            if first_time && !NaN_in_slice(buffer) {
                sum := 0.0
                for j := range buffer {
                    sum += buffer[j]
                }
                output[i] = sum / float64(window_size)
                first_time = false
            } else if i > 0 && !math.IsNaN(output[i-1]) /* && !NaN_in_slice(buffer)*/ {
                output[i] = output[i-1] + (input[i]-old_val)/float64(window_size) // 无循环的解决方案
            } else {
                output[i] = math.NaN()
            }
        }
    } else { // 空输入
        fmt.Println("moving_avg is panicking!")
        panic(fmt.Sprintf("%v", input))
    }
    return output
}

// 返回包含输入移动平均值的列表
// 将列表拆分为较小的片段以使用 goroutine,但不使用串行版本,即我们仅在开头具有 NaN,因此希望减少一些开销
// 仍然不能扩展(随着大小和 num_goroutines 的增加,性能下降)
func moving_avg_concurrent2(input []float64, window_size, num_goroutines int) []float64 {
    var output = make([]float64, window_size-1, len(input))
    for i := 0; i < window_size-1; i++ {
        output[i] = math.NaN()
    }
    if len(input) > 0 {
        num_items := len(input) - (window_size - 1)
        var barrier_wg sync.WaitGroup
        n := num_items / num_goroutines
        go_avg := make([][]float64, num_goroutines)
        for i := 0; i < num_goroutines; i++ {
            go_avg[i] = make([]float64, 0, num_goroutines)
        }

        for i := 0; i < num_goroutines; i++ {
            barrier_wg.Add(1)
            go func(go_id int) {
                defer barrier_wg.Done()

                // 计算边界
                var start, stop int
                start = go_id*int(n) + (window_size - 1) // 开始索引
                // 结束索引
                if go_id != (num_goroutines - 1) {
                    stop = start + n // 结束索引
                } else {
                    stop = num_items + (window_size - 1) // 结束索引
                }

                loc_avg := moving_avg_serial4(input[start-(window_size-1):stop], window_size)

                loc_avg = make([]float64, stop-start)
                current_sum := 0.0
                for i := start - (window_size - 1); i < start+1; i++ {
                    current_sum += input[i]
                }
                loc_avg[0] = current_sum / float64(window_size)
                idx := 1

                for i := start + 1; i < stop; i++ {
                    loc_avg[idx] = loc_avg[idx-1] + (input[i]-input[i-(window_size)])/float64(window_size)
                    idx++
                }

                go_avg[go_id] = append(go_avg[go_id], loc_avg...)

            }(i)
        }
        barrier_wg.Wait()

        for i := 0; i < num_goroutines; i++ {
            output = append(output, go_avg[i]...)
        }

    } else { // 空输入
        fmt.Println("moving_avg is panicking!")
        panic(fmt.Sprintf("%v", input))
    }
    return output
}

// 返回包含输入移动平均值的列表
// 模式改变,我们选择主工作者模式并生成将由 goroutine 计算的每个窗口
func compute_window_avg(input, output []float64, start, end int) {
    sum := 0.0
    size := end - start
    for _, val := range input[start:end] {
        sum += val
    }
    output[end-1] = sum / float64(size)
}

func moving_avg_concurrent3(input []float64, window_size, num_goroutines int) []float64 {
    var output = make([]float64, window_size-1, len(input))
    for i := 0; i < window_size-1; i++ {
        output[i] = math.NaN()
    }
    if len(input) > 0 {
        num_windows := len(input) - (window_size - 1)
        var output = make([]float64, len(input))
        for i := 0; i < window_size-1; i++ {
로그인 후 복사

위 내용은 목록을 개별 고루틴에 의해 처리되는 더 작은 덩어리로 분할했음에도 불구하고 'moving_avg_concurrent2'의 성능이 동시성이 향상되지 않는 이유는 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿