Maison > Article > développement back-end > Les programmes Go ralentissent lorsque le nombre de goroutines augmente
Lorsque le nombre de goroutines augmente, les programmes Go ralentissent. En effet, la planification et la commutation des goroutines introduiront une surcharge supplémentaire, entraînant une réduction des performances du programme. Bien que les goroutines soient excellentes pour fournir des performances de concurrence, un trop grand nombre de goroutines peut entraîner une concurrence entre les threads et des conflits de ressources, affectant ainsi l'efficacité d'exécution du programme. Afin d'éviter que cette situation ne se produise, nous devons gérer et contrôler raisonnablement le nombre de goroutines pour garantir que le programme peut fonctionner efficacement. Dans cet article, l'éditeur PHP Youzi vous présentera quelques méthodes et techniques d'optimisation des performances des goroutines pour vous aider à améliorer l'efficacité d'exécution des programmes Go.
Je travaille sur un petit projet pour mon cours de parallélisme et j'ai essayé d'utiliser des canaux tamponnés, des canaux non tamponnés, des canaux sans utiliser de pointeurs vers des tranches, etc. J'ai également essayé de l'optimiser autant que possible (pas l'état actuel) mais j'obtiens toujours le même résultat : augmenter le nombre de goroutines (même de 1) ralentit tout le programme. Quelqu'un peut-il me dire ce que je fais de mal ? Est-il même possible d’améliorer le parallélisme dans ce cas ?
Ceci fait partie du code :
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 }
On s'attendait à ce qu'en augmentant le nombre de goroutines, le programme s'exécuterait plus rapidement, mais jusqu'à un certain nombre de goroutines, auquel cas en augmentant le nombre de goroutines, j'obtiendrais le même temps d'exécution ou légèrement plus lent.
EDIT : Toutes les fonctionnalités utilisées :
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)) }
En termes simples, le code de génération de fichiers n'est pas suffisamment complexe pour justifier une exécution parallèle. Tous les changements de contexte et tous les déplacements de données via des canaux consomment tous les avantages du traitement parallèle.
Si vous regardez le contenu de generatefiles
函数的循环中添加类似 time.sleep(time.millisecond * 10)
comme s'il s'agissait de quelque chose de plus complexe, vous verrez ce à quoi vous vous attendez : plus de goroutines fonctionnent plus rapidement. Mais encore une fois, ce n’est que jusqu’à un certain point que le travail supplémentaire du traitement parallèle est payant.
A noter également, le temps d'exécution du dernier bit du programme :
for i := 0; i < numAgents; i++ { files = append(files, <-channel...) }
Dépend directement du nombre de goroutines. Étant donné que toutes les goroutines se terminent à peu près au même moment, la boucle s'exécute rarement en parallèle avec vos threads de travail, et le temps nécessaire à son exécution est simplement ajouté au temps total.
Ensuite, lorsque vous ajoutez plusieurs fois à une tranche files
, celle-ci doit s'agrandir plusieurs fois et copier les données vers le nouvel emplacement. Vous pouvez éviter cela en créant initialement une tranche qui remplit tous les éléments du résultat (heureusement, vous savez exactement combien d'éléments sont nécessaires).
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!