Горутины не масштабируются линейно, но программы Go делают? - PullRequest
0 голосов
/ 14 января 2020

Я ищу несколько общих советов по оптимизации производительности.

У меня довольно сложный фрагмент кода, но код живет в функции (без глобальных), поэтому я могу либо a) вызвать эта функция в нескольких программах (у меня на машине 12 ядер). Или б) используйте функцию такого же типа, которая вызывается один раз, скомпилируйте мою go программу и выполните все это 4 раза параллельно.

Вот пример кода с таким же поведением:

package main

import (
    "fmt"
    "runtime"
    "time"
)

const size = 140000

type BigStruct struct {
    first  []int
    second []int
}

func slowFunc() int {
    // make local variables
    sum := 0
    myData := BigStruct{}
    myData.first = make([]int, 0, size)

    // fill some slices 
    for i := 0; i < size; i++ {
        myData.first = append(myData.first, i)
        myData.second = append(myData.second, i)
    }

    // do pointless calculations
    for i := range myData.first {
        for j := range
            myData.second {
            if myData.first[i] == myData.second[j] {
                sum++
            }
        }

    }
    return sum
}

func slowFuncChan(output chan int) {
    // make local variables
    sum := 0
    myData := BigStruct{}
    myData.first = make([]int, 0, size)

    // fill some slices 
    for i := 0; i < size; i++ {
        myData.first = append(myData.first, i)
        myData.second = append(myData.second, i)
    }

    // do pointless calculations
    for i := range myData.first {
        for j := range
            myData.second {
            if myData.first[i] == myData.second[j] {
                sum++
            }
        }

    }
    output <- sum
}

func main() {

    numCPUs := runtime.NumCPU()
    runtime.GOMAXPROCS(numCPUs)
    fmt.Println("numCPUs: ", numCPUs)

    fmt.Println("Calling slowFunc once...")

    start := time.Now()
    fmt.Println("sum: ", slowFunc())
    t := time.Now() // test
    elapsed := t.Sub(start)
    fmt.Println("time elapsed: ", elapsed)
    fmt.Println()


    fmt.Println("Calling slowFunc 4x in goroutines...")

    output := make(chan int, 4)
    for w := 0; w < 4; w++ {
        go slowFuncChan(output)
    }

    for a := 0; a < 4; a++ {
        fmt.Println("sum: ", <-output)
    }

    t2 := time.Now() // test
    elapsed = t2.Sub(t)
    fmt.Println("time elapsed: ", elapsed)
}

Когда я использую 4 программы, это занимает примерно 2 раза больше, а скомпилированная программа запускается в 4 раза параллельно! И 4 копии программы, работающей параллельно, похоже, работают немного медленнее, чем одна работающая версия, то есть очень хорошо масштабируются.

Это вывод одной программы:

numCPUs:  12
Calling slowFunc once...
sum:  140000
time elapsed:  10.8093226s
Calling slowFunc 4x in goroutines...
sum:  140000
sum:  140000
sum:  140000
sum:  140000
time elapsed:  22.4335858s

Используя командный файл, я запускаю программу 4 раза одновременно и получаю 4 результата:

numCPUs:  12
Calling slowFunc once...
sum:  140000
time elapsed:  12.7615683s

,

numCPUs:  12
Calling slowFunc once...
sum:  140000
time elapsed:  12.7705668s

,

numCPUs:  12
Calling slowFunc once...
sum:  140000
time elapsed:  12.2635664s

,

numCPUs:  12
Calling slowFunc once...
sum:  140000
time elapsed:  12.1155655s

Общее время запуска 4-х одновременных программ составляет 12,7705668 с и почти вдвое меньше, чем у версии с программами (22.4335858s)

Я проверил это с 8 программами по сравнению с 8 одновременными программами, и получили тот же результат с несколькими приложениями, работающими в 2 раза по сравнению с одной версией программы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...