Heim  >  Artikel  >  Backend-Entwicklung  >  Go-Programme werden langsamer, wenn die Anzahl der Goroutinen zunimmt

Go-Programme werden langsamer, wenn die Anzahl der Goroutinen zunimmt

WBOY
WBOYnach vorne
2024-02-09 22:10:101256Durchsuche

当 goroutine 数量增加时,Go 程序会变慢

Wenn die Anzahl der Goroutinen zunimmt, werden Go-Programme langsamer. Dies liegt daran, dass die Goroutine-Planung und -Umschaltung zusätzlichen Overhead mit sich bringt, was zu einer verringerten Programmleistung führt. Obwohl Goroutinen eine hervorragende Parallelitätsleistung bieten, können zu viele Goroutinen zu Thread-Konkurrenz und Ressourcenkonflikten führen und dadurch die Ausführungseffizienz des Programms beeinträchtigen. Um diese Situation zu vermeiden, müssen wir die Anzahl der Goroutinen angemessen verwalten und kontrollieren, um sicherzustellen, dass das Programm effizient ausgeführt werden kann. In diesem Artikel stellt Ihnen der PHP-Editor Youzi einige Methoden und Techniken zur Optimierung der Goroutine-Leistung vor, um Ihnen dabei zu helfen, die Ausführungseffizienz von Go-Programmen zu verbessern.

Frageninhalt

Ich arbeite an einem kleinen Projekt für meinen Parallelitätskurs und habe versucht, gepufferte Kanäle, ungepufferte Kanäle, Kanäle ohne Zeiger auf Slices usw. zu verwenden. Außerdem habe ich versucht, es so weit wie möglich zu optimieren (nicht den aktuellen Stand), aber ich erhalte immer noch das gleiche Ergebnis: Eine Erhöhung der Anzahl der Goroutinen (sogar um 1) verlangsamt das gesamte Programm. Kann mir jemand sagen, was ich falsch mache? Ist es in diesem Fall überhaupt möglich, die Parallelität zu verbessern?

Dies ist Teil des Codes:

func main() {

    rand.seed(time.now().unixmicro())

    numagents := 2

    fmt.println("please pick a number of goroutines: ")
    fmt.scanf("%d", &numagents)

    numfiles := 4
    fmt.println("how many files do you want?")
    fmt.scanf("%d", &numfiles)
    start := time.now()

    numassist := numfiles
    channel := make(chan []file, numagents)
    files := make([]file, 0)

    for i := 0; i < numagents; i++ {
        if i == numagents-1 {
            go generatefiles(numassist, channel)
        } else {
            go generatefiles(numfiles/numagents, channel)
            numassist -= numfiles / numagents
        }
    }

    for i := 0; i < numagents; i++ {
        files = append(files, <-channel...)
    }

    elapsed := time.since(start)
    fmt.printf("function took %s\n", elapsed)
}
func generatefiles(numfiles int, channel chan []file) {
    magicnumbersmap := getmap()
    files := make([]file, 0)

    for i := 0; i < numfiles; i++ {
        content := randelementfrommap(&magicnumbersmap)

        length := rand.intn(400) + 100
        hexslice := gethex()

        for j := 0; j < length; j++ {
            content = content + hexslice[rand.intn(len(hexslice))]
        }

        hash := getsha1hash([]byte(content))

        file := file{
            content: content,
            hash:    hash,
        }

        files = append(files, file)
    }

    channel <- files

}

Es wurde erwartet, dass das Programm durch die Erhöhung der Goroutinen schneller laufen würde, aber bis zu einer bestimmten Anzahl von Goroutinen, ab diesem Punkt würde ich durch die Erhöhung der Goroutinen die gleiche Ausführungszeit oder etwas langsamer erreichen.

EDIT: Alle verwendeten Funktionen:

import (
    "crypto/sha1"
    "encoding/base64"
    "fmt"
    "math/rand"
    "time"
)

type File struct {
    content string
    hash    string
}

func getMap() map[string]string {
    return map[string]string{
        "D4C3B2A1": "Libcap file format",
        "EDABEEDB": "RedHat Package Manager (RPM) package",
        "4C5A4950": "lzip compressed file",
    }
}

func getHex() []string {
    return []string{
        "0", "1", "2", "3", "4", "5",
        "6", "7", "8", "9", "A", "B",
        "C", "D", "E", "F",
    }
}

func randElementFromMap(m *map[string]string) string {
    x := rand.Intn(len(*m))
    for k := range *m {
        if x == 0 {
            return k
        }
        x--
    }
    return "Error"
}

func getSHA1Hash(content []byte) string {
    h := sha1.New()
    h.Write(content)
    return base64.URLEncoding.EncodeToString(h.Sum(nil))
}

Lösung

Einfach ausgedrückt: Der Dateigenerierungscode ist nicht komplex genug, um eine parallele Ausführung zu rechtfertigen. Bei jedem Kontextwechsel und dem Verschieben von Daten durch Kanäle werden alle Vorteile der Parallelverarbeitung genutzt.

Wenn Sie den Inhalt von generatefiles 函数的循环中添加类似 time.sleep(time.millisecond * 10) betrachten, als ob er etwas Komplexeres tun würde, werden Sie sehen, was Sie erwarten würden – mehr Goroutinen funktionieren schneller. Aber auch hier gilt: Nur bis zu einem gewissen Punkt lohnt sich der Mehraufwand der Parallelverarbeitung.

Beachten Sie auch die Ausführungszeit des letzten Programmteils:

for i := 0; i < numAgents; i++ {
    files = append(files, <-channel...)
}

Hängt direkt von der Anzahl der Goroutinen ab. Da alle Goroutinen ungefähr zur gleichen Zeit enden, wird die Schleife selten parallel zu Ihren Arbeitsthreads ausgeführt und die für die Ausführung benötigte Zeit wird nur zur Gesamtzeit addiert.

Wenn Sie als nächstes mehrmals an ein files-Slice anhängen, muss es mehrmals wachsen und die Daten an den neuen Speicherort kopieren. Sie können dies vermeiden, indem Sie zunächst ein Slice erstellen, das alle Ergebniselemente füllt (zum Glück wissen Sie genau, wie viele Elemente benötigt werden).

Das obige ist der detaillierte Inhalt vonGo-Programme werden langsamer, wenn die Anzahl der Goroutinen zunimmt. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen