Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Program Go menjadi perlahan apabila bilangan goroutine meningkat

Program Go menjadi perlahan apabila bilangan goroutine meningkat

WBOY
WBOYke hadapan
2024-02-09 22:10:101289semak imbas

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

Apabila bilangan goroutine bertambah, program Go akan menjadi perlahan. Ini kerana penjadualan dan penukaran goroutine akan memperkenalkan overhed tambahan, mengakibatkan prestasi program berkurangan. Walaupun goroutin sangat baik dalam menyediakan prestasi serentak, terlalu banyak goroutin boleh membawa kepada persaingan benang dan pertikaian sumber, sekali gus menjejaskan kecekapan pelaksanaan program. Bagi mengelak situasi ini berlaku, kita perlu mengurus dan mengawal bilangan goroutin secara munasabah bagi memastikan program dapat berjalan dengan cekap. Dalam artikel ini, editor PHP Youzi akan memperkenalkan anda kepada beberapa kaedah dan teknik untuk mengoptimumkan prestasi goroutine untuk membantu anda meningkatkan kecekapan pelaksanaan program Go.

Kandungan soalan

Saya sedang mengusahakan projek kecil untuk kursus paralelisme saya dan saya telah mencuba menggunakan saluran buffer, saluran tidak buffer, saluran tanpa menggunakan penunjuk kepada kepingan, dsb. Juga, cuba mengoptimumkannya sebanyak mungkin (bukan keadaan semasa) tetapi saya masih mendapat hasil yang sama: meningkatkan bilangan goroutine (walaupun sebanyak 1) memperlahankan keseluruhan program. Bolehkah seseorang memberitahu saya apa yang saya lakukan salah? Adakah mungkin untuk meningkatkan paralelisme dalam kes ini?

Ini adalah sebahagian daripada kod:

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

}

Dijangkakan bahawa dengan meningkatkan goroutin, program akan berjalan lebih pantas, tetapi sehingga bilangan goroutin tertentu, pada ketika itu dengan meningkatkan goroutin, saya akan mendapat masa pelaksanaan yang sama atau lebih perlahan.

EDIT: Semua ciri yang digunakan:

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))
}

Penyelesaian

Ringkasnya - kod penjanaan fail tidak cukup kompleks untuk mewajarkan pelaksanaan selari. Semua penukaran konteks dan memindahkan data melalui saluran menggunakan semua faedah pemprosesan selari.

Jika anda melihat kandungan generatefiles 函数的循环中添加类似 time.sleep(time.millisecond * 10) seolah-olah ia melakukan sesuatu yang lebih kompleks, anda akan melihat perkara yang anda jangkakan untuk melihat - lebih banyak goroutin berfungsi dengan lebih pantas. Tetapi sekali lagi, hanya sehingga satu tahap tertentu sahaja kerja tambahan pemprosesan selari membuahkan hasil.

Juga ambil perhatian, masa pelaksanaan bit terakhir program:

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

Secara langsung bergantung kepada bilangan goroutin. Memandangkan semua goroutine selesai pada masa yang sama, gelung jarang dilaksanakan selari dengan urutan pekerja anda dan masa yang diperlukan untuk dijalankan hanya ditambah kepada jumlah masa.

Seterusnya, apabila anda menambah files kepingan beberapa kali, ia perlu membesar beberapa kali dan menyalin data ke lokasi baharu. Anda boleh mengelakkan ini dengan mula membuat kepingan yang mengisi semua elemen hasil (nasib baik anda tahu dengan tepat berapa banyak elemen yang diperlukan).

Atas ialah kandungan terperinci Program Go menjadi perlahan apabila bilangan goroutine meningkat. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:stackoverflow.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam