web-dev-qa-db-fra.com

Traitement parallèle à Golang

Étant donné le code suivant:

package main

import (
    "fmt"
    "math/Rand"
    "time"
)

func main() {
    for i := 0; i < 3; i++ {
        go f(i)
    }

    // prevent main from exiting immediately
    var input string
    fmt.Scanln(&input)
}

func f(n int) {
    for i := 0; i < 10; i++ {
        dowork(n, i)
        amt := time.Duration(Rand.Intn(250))
        time.Sleep(time.Millisecond * amt)
    }
}

func dowork(goroutine, loopindex int) {
    // simulate work
    time.Sleep(time.Second * time.Duration(5))
    fmt.Printf("gr[%d]: i=%d\n", goroutine, loopindex)
}

Puis-je supposer que la fonction 'dowork' sera exécutée en parallèle?

Est-ce une façon correcte d’atteindre le parallélisme ou est-il préférable d’utiliser des canaux et de séparer les travailleurs de «travail en équipe» pour chaque goroutine?

6
wilsonfiifi

Votre code sera exécuté simultanément, mais pas en parallèle. Vous pouvez le faire fonctionner en parallèle en définissant GOMAXPROCS; voir l'article https://www.ardanlabs.com/blog/2014/01/concurrency-goroutines-and-gomaxprocs.html pour un bon résumé.

Ce que vous essayez d'accomplir ici n'est pas clair, mais cela me semble être un moyen tout à fait valable de parvenir à la concurrence.

14
Evan

En ce qui concerne GOMAXPROCS, vous pouvez le trouver dans la documentation de Go 1.5:

Par défaut, les programmes Go s'exécutent avec GOMAXPROCS défini sur le nombre de cœurs disponibles. dans les versions précédentes, la valeur par défaut était 1.

Pour empêcher la sortie de la fonction main immédiatement, vous pouvez utiliser la fonction WaitGroup de Wait.

J'ai écrit cette fonction utilitaire pour aider à paralléliser un groupe de fonctions:

import "sync"

// Parallelize parallelizes the function calls
func Parallelize(functions ...func()) {
    var waitGroup sync.WaitGroup
    waitGroup.Add(len(functions))

    defer waitGroup.Wait()

    for _, function := range functions {
        go func(copy func()) {
            defer waitGroup.Done()
            copy()
        }(function)
    }
}

Donc, dans votre cas, nous pourrions le faire

func1 := func() {
    f(0)
}

func2 = func() {
    f(1)
}

func3 = func() {
    f(2)
}

Parallelize(func1, func2, func3)

Si vous souhaitez utiliser la fonction Paralléliser, vous pouvez la trouver ici https://github.com/shomali11/util

5
Raed Shomali

Cela m'a aidé quand je débutais.

    package main

    import "fmt"

    func put(number chan<- int, count int) {
        i := 0
        for ; i <= (5 * count); i++ {
            number <- i
        }
        number <- -1
    }

    func subs(number chan<- int) {
        i := 10
        for ; i <= 19; i++ {
            number <- i
        }
    }

    func main() {
        channel1 := make(chan int)
        channel2 := make(chan int)
        done := 0
        sum := 0

        go subs(channel2)
        go put(channel1, 1)
        go put(channel1, 2)
        go put(channel1, 3)
        go put(channel1, 4)
        go put(channel1, 5)

        for done != 5 {
            select {
            case elem := <-channel1:
                if elem < 0 {
                    done++
                } else {
                    sum += elem
                    fmt.Println(sum)
                }
            case sub := <-channel2:
                sum -= sub
                fmt.Printf("atimta : %d\n", sub)
                fmt.Println(sum)
            }
        }
        close(channel1)
        close(channel2)
    }

"Les systèmes classiques basés sur des clusters (tels que les superordinateurs) utilisent une exécution parallèle entre les processeurs utilisant MPI. MPI est une interface de communication entre les processus qui s'exécutent dans des instances de système d'exploitation sur différents processeurs; elle ne prend pas en charge d'autres opérations de processus. tels que la planification (au risque de compliquer davantage les choses, car les processus MPI sont exécutés par des systèmes d'exploitation, un seul processeur peut exécuter plusieurs processus MPI et/ou un seul MPI processus peut également exécuter plusieurs threads!) "

0
Wolfie

f() sera exécuté simultanément mais plusieurs dowork() seront exécutés séquentiellement dans chaque f(). Attendre stdin n’est pas non plus une bonne façon de s’assurer que vos routines ont été exécutées. Vous devez créer un canal sur lequel chaque f() ajoute un true à la fin de la f(). À la fin de la main(), vous devez attendre n nombre de true 'sur le canal. n étant le nombre de f() que vous avez démarré.

0