2016-08-19 8 views
0

Gestern habe ich eine Frage mit fast demselben Code gestellt und gefragt, wie man dies unter einer variadischen Funktion gleichzeitig machen könnte. Nachdem es gelöst wurde, erwartete ich, dass das Programm fast die gleiche Zeit mit einem Generator wie mit 30+ läuft. Es scheint nicht so.Warum ist das bei Goroutines so langsam?

Die Zeiten, die ich sehe, sind mit einem Generator, etwa 5 ms. Mit, was in dem Code unten ist, 150ms. (Aus irgendeinem Grund zeigt play.golang 0).

Warum ist es langsamer? Ich hatte die Erwartung, dass es mit den vielen Goroutines ungefähr so ​​lange dauern würde. Etwas, das damit zu tun hat, die Goroutines zu drehen?

package main 

import (
    "fmt" 
    "sync" 
    "time" 
) 

func main() { 
    t := time.Now() 
    _ = fanIn(
     generator(4, 5, 6, 7), 
     generator(1, 2, 6, 3, 7), 
     generator(12, 15, 33, 40, 10), 
     generator(18, 13, 20, 40, 15), 
     generator(100, 200, 64000, 3121, 1237), 
     generator(4, 5, 6, 7), 
     generator(1, 2, 6, 3, 7), 
     generator(12, 15, 33, 40, 10), 
     generator(18, 13, 20, 40, 15), 
     generator(100, 200, 64000, 3121, 1237), 
     generator(4, 5, 6, 7), 
     generator(1, 2, 6, 3, 7), 
     generator(12, 15, 33, 40, 10), 
     generator(18, 13, 20, 40, 15), 
     generator(100, 200, 64000, 3121, 1237), 
     generator(4, 5, 6, 7), 
     generator(1, 2, 6, 3, 7), 
     generator(12, 15, 33, 40, 10), 
     generator(18, 13, 20, 40, 15), 
     generator(100, 200, 64000, 3121, 1237), 
     generator(4, 5, 6, 7), 
     generator(1, 2, 6, 3, 7), 
     generator(12, 15, 33, 40, 10), 
     generator(18, 13, 20, 40, 15), 
     generator(100, 200, 64000, 3121, 1237), 
     generator(4, 5, 6, 7), 
     generator(1, 2, 6, 3, 7), 
     generator(12, 15, 33, 40, 10), 
     generator(18, 13, 20, 40, 15), 
     generator(100, 200, 64000, 3121, 1237), 
     generator(4, 5, 6, 7), 
     generator(1, 2, 6, 3, 7), 
     generator(12, 15, 33, 40, 10), 
     generator(18, 13, 20, 40, 15), 
     generator(100, 200, 64000, 3121, 1237), 
    ) 

    fmt.Println(time.Now().Sub(t)) 
} 

func generator(nums ...int) <-chan int { 
    out := make(chan int, 10) 
    go func() { 
     defer close(out) 
     for _, v := range nums { 
      out <- v 
     } 
    }() 
    return out 
} 

func fanIn(in ...<-chan int) <-chan int { 
    var wg sync.WaitGroup 
    out := make(chan int, 10) 
    wg.Add(len(in)) 

    go func() { 
     for _, v := range in { 
      go func(ch <-chan int) { 
       defer wg.Done() 
       for val := range ch { 
        out <- val 
       } 
      }(v) 
     } 

    }() 
    go func() { 
     wg.Wait() 
     close(out) 
    }() 
    return out 
} 
+1

Was ist Ihre Go-Version ist, und wie viele CPU-Kerne Sie haben, für mich ist es weniger als 1 ms. –

+0

Ich habe Go-Version Go1.6.2 Darwin/AMD64, MBP 2.9 GHz Intel Core i5. –

+0

Auch ich laufe das mit 'Go run' anstatt zu installieren, was ich glaube, ist das langsamste. Der Test war nicht, es schnell laufen zu lassen, es war zu sehen, ob ich mehrere Generatoren mit der gleichen Geschwindigkeit laufen lassen kann. Nur zu deiner Information. –

Antwort

2

Es gibt einen kleinen Unterschied zwischen go run und go build (Kompilierung):
für mich 17ms (2 Cores) und 3ms (auf 8 Cores) mit go1.7 amd64:

Unterschied zwischen go run und go build :
951.0543ms-934.0535ms = 17.0008ms (auf 2 Kernen)
575,3447ms-572.3914ms = 2.9533ms (auf 8 Cores)

Differenz zwischen 8 Cores und 2 Adern mit go build:
934.0535ms-572.3914ms = 361.6621ms

Für eine gute Benchmark-Statistiken, verwenden große Anzahl von Proben.
versuchen Sie ein Update auf die neueste Go-Version (1.7).

Versuchen Sie, diesen Arbeitsbeispielcode und vergleichen Sie das Ergebnis mit diesen Ausgängen:

package main 

import (
    "fmt" 
    "math/rand" 
    "sync" 
    "time" 
) 

func main() { 
    t := time.Now() 
    cs := make([]<-chan int, 1000) 
    for i := 0; i < len(cs); i++ { 
     cs[i] = generator(rand.Perm(10000)...) 
    } 
    ch := fanIn(cs...) 
    fmt.Println(time.Now().Sub(t)) 

    is := make([]int, 0, len(ch)) 
    for v := range ch { 
     is = append(is, v) 
    } 
    fmt.Println("len=", len(is)) 
} 

func generator(nums ...int) <-chan int { 
    out := make(chan int, len(nums)) 
    go func() { 
     defer close(out) 
     for _, v := range nums { 
      out <- v 
     } 
    }() 
    return out 
} 

func fanIn(in ...<-chan int) <-chan int { 
    var wg sync.WaitGroup 
    out := make(chan int, 10) 
    wg.Add(len(in)) 

    go func() { 
     for _, v := range in { 
      go func(ch <-chan int) { 
       defer wg.Done() 
       for val := range ch { 
        out <- val 
       } 
      }(v) 
     } 

    }() 
    go func() { 
     wg.Wait() 
     close(out) 
    }() 
    return out 
} 

Ausgang mit 2 Cores (mit go run):

951.0543ms 
len= 10000000 

Ausgang mit 2 Cores (mit go build):

934.0535ms 
len= 10000000 

Ausgabe mit 8 Kernen (mit go run):

575.3447ms 
len= 10000000 

Ausgang mit 8 Cores (mit go build):

572.3914ms 
len= 10000000 
+0

@ Nathan-Hyland Ich hoffe, das hilft. –