strange behaviour of goroutines in for loop [duplicate] - for-loop

This question already has answers here:
Strange golang "append" behavior (overwriting values in slice)
(3 answers)
Closed 2 years ago.
I am switching from Python to GoLang. I was learning goroutines. I faced strange outputs when I used the goroutines in for loop.
package main
import "fmt"
func main() {
var test = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40}
for _, x := range test{
go func() {
fmt.Println(x)
}()
}
}
the output:
25
19
28
19
40
40
6
I was thinking it was capturing values from for loop but, when I saw it was increasing and decreasing. I got confused. Why is that happening?

The goroutines are accessing the x variable that is changing in parallel with the execution of the goroutines. This is a common problem encountered by I think even go programmer at least once. You can capture the current value of the variable like this:
for _, x := range test{
go func(x int) {
fmt.Println(x)
}(x)
}
Or like this:
for _, x := range test{
x2 := x
go func() {
fmt.Println(x2)
}()
}

Related

Finding numbers above the mean

I could use some help finding all the numbers from a struct array that are above a calculated mean!
//MeanMedianMode struct
type MeanMedianMode struct {
numbers []float64
}
func main() {
// range of numbers
dataType := MeanMedianMode{
numbers: []float64{
84, 25, 88, 56, 10, 19, 11, 80,
45, 83, 22, 40, 22, 52, 61, 13, 73, 23, //Data to be used
90, 89, 6,
},
}
I've figured out how to pass my data easily and find the average as follows...
//CalcMean float64
func (mm *MeanMedianMode) CalcMean() float64 {
total := 0.0
for _, v := range mm.numbers {
total += v
}
return (total / float64(len(mm.numbers)))
//return math.Round(total / float64(len(mm.numbers))) //Should it need to be rounded
}
My biggest issue is replicating that process and using the values stored in the array within another function and iterating over them to find the values greater than (>) the found mean!
I appreciate the insights!
I don't know how you'd like to do it, but something like this I guess:
package main
import (
"fmt"
)
//MeanMedianMode struct
type MeanMedianMode struct {
numbers []float64
}
func main() {
m := &MeanMedianMode{
numbers: []float64{
84, 25, 88, 56, 10, 19, 11, 80,
45, 83, 22, 40, 22, 52, 61, 13, 73, 23,
90, 89, 6,
},
}
mean := m.CalcMean()
for _, n := range m.numbers {
if n > mean {
fmt.Printf("%.3f is greater than the mean\n", n)
}
}
}
//CalcMean float64
func (mm *MeanMedianMode) CalcMean() float64 {
total := 0.0
for _, v := range mm.numbers {
total += v
}
return (total / float64(len(mm.numbers)))
}

Go code running result in local environment is not same with run in go play

I am using Go to implement an algorithm described below:
There is an array,only one number appear one time,all the other numbers appear three times,find the number only appear one time
My code listed below:
import (
"testing"
)
func findBySum(arr []int) int {
result := 0
sum := [32]int{}
for i := 0; i < 32; i++ {
for _, v := range arr {
sum[i] += (v >> uint(i)) & 0x1
}
sum[i] %= 3
sum[i] <<= uint(i)
result |= sum[i]
}
return result
}
func TestThree(t *testing.T) {
// except one nubmer,all other number appear three times
a1 := []int{11, 222, 444, 444, 222, 11, 11, 17, -123, 222, -123, 444, -123} // unqiue number is 17
a2 := []int{11, 222, 444, 444, 222, 11, 11, -17, -123, 222, -123, 444, -123} // unque number is -17
t.Log(findBySum(a1))
t.Log(findBySum(a2))
}
However,I found that the running result in my PC is wrong,and the same code running in https://play.golang.org/p/hEseLZVL617 is correct,I do not know why.
Result in my PC:
Result in https://play.golang.org/p/hEseLZVL617:
As we see,when the unique number is positive,both result are right,but when the unique number is negative,the result in my PC in wrong and the result online is right.
I think it has something to do with the bit operations in my code,but I can't find the root cause.
I used IDEA 2019.1.1 and my Golang version listed below:
I don't know why the same code can works fine online and do not work in my local PC,can anyone help me analysis this? Thanks in advance!
Size of int is platform dependent, it may be 32-bit and it may be 64-bit. On the Go Playground it's 32-bit, on your local machine it's 64-bit.
If we change your example to use int64 explicitly instead of int, the result is the same on the Go Playground too:
func findBySum(arr []int64) int64 {
result := int64(0)
sum := [32]int64{}
for i := int64(0); i < 32; i++ {
for _, v := range arr {
sum[i] += (v >> uint64(i)) & 0x1
}
sum[i] %= 3
sum[i] <<= uint(i)
result |= sum[i]
}
return result
}
func TestThree(t *testing.T) {
// except one nubmer,all other number appear three times
a1 := []int64{11, 222, 444, 444, 222, 11, 11, 17, -123, 222, -123, 444, -123} // unqiue number is 17
a2 := []int64{11, 222, 444, 444, 222, 11, 11, -17, -123, 222, -123, 444, -123} // unque number is -17
t.Log(findBySum(a1))
t.Log(findBySum(a2))
}
You perform bitwise operations that assume 32-bit integer size. To get correct results locally (where your architecture and thus size of int and uint is 64-bit), change all ints to int32 and uint to uint32:
func findBySum(arr []int32) int32 {
result := int32(0)
sum := [32]int32{}
for i := int32(0); i < 32; i++ {
for _, v := range arr {
sum[i] += (v >> uint32(i)) & 0x1
}
sum[i] %= 3
sum[i] <<= uint(i)
result |= sum[i]
}
return result
}
func TestThree(t *testing.T) {
// except one nubmer,all other number appear three times
a1 := []int32{11, 222, 444, 444, 222, 11, 11, 17, -123, 222, -123, 444, -123} // unqiue number is 17
a2 := []int32{11, 222, 444, 444, 222, 11, 11, -17, -123, 222, -123, 444, -123} // unque number is -17
t.Log(findBySum(a1))
t.Log(findBySum(a2))
}
Lesson: if you perform calculations whose result depend on the representation size, always be explicit, and use fixed-size numbers like int32, int64, uint32, uint64.

Difficulty with variadic functions [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
From An Introduction to Programming in Go, page 91, Exercise Question no 4, Topic: Functions:
Write a function with one variadic parameter that finds the greatest number in a list of numbers?
So far I had written this code but it is showing errors
package main
import (
"fmt"
)
func findMaximum(args ...[]int) []int {
max := args[0]
for _, v := range args {
if v > []args {
max = v
}
}
return args
}
func main() {
x := []int{
48, 96, 86, 68,
57, 82, 63, 70,
37, 34, 83, 27,
19, 97, 9, 17,
}
fmt.Println(findMaximum(x))
}
I had taken reference from this Program
(Page, 75, Question No. - 4, Topic: Arrays, Slices and Maps)
Write a program that finds the smallest number
in this list:
x := []int{
48,96,86,68,
57,82,63,70,
37,34,83,27,
19,97, 9,17,
}
This is the program I had written to solve this Question
package main
import "fmt"
func main() {
arr := []uint{
48, 96, 86, 68,
57, 82, 63, 70,
37, 34, 83, 27,
19, 97, 9, 17,
}
min := arr[0] // assume first value is smallest
for _, value := range arr {
if value < min {
min = value // found another value, replace previous value of min
}
}
fmt.Println("The smallest value is : ", min)
}
This Question Program is running but the First one is not I don't know why.
In mathematics and in computer programming, a variadic function is a
function of indefinite arity, i.e., one which accepts a variable
number of arguments.
Source: Wikipedia
Your function signature is slightly incorrect.
func findMaximum(args ...[]int) []int
This indicates that findMaximum takes in a variable number of int slices as arguments and returns an int slice. The problem that you're trying to solve is asking to take in a variable number of int arguments and return a singular int which is the largest in the set provided.
Calling your function would look something like this:
largest := findMaximum([]int{1, 2, 3}, []int{4, 5, 6}, []int{7, 8, 9})
In this case, largest would be of type []int indicating that the function returned multiple int values in the form of a slice. This wouldn't make sense, since there should only be one largest value (assuming no duplicates).
You're wanting a function signature that looks like this:
func findMaximum(args ...int) int
Calling this function would look like this:
largest := findMaximum(1, 2, 3, 4, 5, 6, 7, 8, 9)
...or if you had your numbers in a slice:
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
largest := findMaximum(nums...)
In this case, largest would be of type int, which is the correct return value you're looking for in this problem.
(Go Playground)
Good luck!
If you run your code through https://play.golang.org/ you will see a couple of syntax errors. Below is the correct version which finds max in a slice.
As you can note you had extra ... in the slice argument call.
package main
import (
"fmt"
)
func findMaximum(args []int) int {
max := args[0]
for _, v := range args {
if v > max{
max = v
}
}
return max
}
func main() {
x := []int{
48, 96, 86, 68,
57, 82, 63, 70,
37, 34, 83, 27,
19, 97, 9, 17,
}
fmt.Println(findMaximum(x))
}

go random generator stops working after some calls

I want shuffle db ids so that none of the id refer to themselves, but with this piece of code:
package main
import (
"log"
"math/rand"
"time"
)
func main() {
seed := time.Now().UnixNano() & 999999999
log.Print("seed: ", seed)
rand.Seed(seed)
ordered := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
randomized := shufflePreventCollision(ordered)
log.Print("Final Result")
log.Print("ordered: ", ordered)
log.Print("random: ", randomized)
}
func shufflePreventCollision(ordered []int) []int {
randomized := rand.Perm(len(ordered))
for i, o := range ordered {
if o == randomized[i] {
log.Printf("Doing it again because ordered[%d] (%d) is == randomized[%d] (%d)", i, o, i, randomized[i])
log.Print(ordered)
log.Print(randomized)
shufflePreventCollision(ordered)
}
}
return randomized
}
I find a strange behaviour, when it runs often it at some point hangs and cannot find non-colliding sequences anymore. I tried
go build -o rand_example3 rand_example3.go && time (for i in $(seq 10000) ; do ./rand_example3 ; done)
And it seems to never end. Am I missing some understanding here or is there really something fishy with math/rand?
"With this piece of code, I want shuffle db ids so that none of the
ids refer to themselves. [Sometimes] it doesn't end even when I let it
run for an hour or so."
tl;dr There is a faster solution that is more than a thousand times faster.
Your code:
slaxor.go:
package main
import (
"log"
"math/rand"
"time"
)
func main() {
seed := time.Now().UnixNano() & 999999999
log.Print("seed: ", seed)
rand.Seed(seed)
ordered := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
randomized := shufflePreventCollisionSlaxor(ordered)
log.Print("Final Result")
log.Print("ordered: ", ordered)
log.Print("random: ", randomized)
}
func shufflePreventCollisionSlaxor(ordered []int) []int {
randomized := rand.Perm(len(ordered))
for i, o := range ordered {
if o == randomized[i] {
log.Printf("Doing it again because ordered[%d] (%d) is == randomized[%d] (%d)", i, o, i, randomized[i])
log.Print(ordered)
log.Print(randomized)
shufflePreventCollisionSlaxor(ordered)
}
}
return randomized
}
Playground: https://play.golang.org/p/JI5rJGcAAz
It is not obvious how, or even if, the code fulfills its purpose.
The termination condition is probabalistic, not deterministic.
Let's leave aside the issue of whether the code fulfills its purpose.
This benchmark has been modified so that stderr is limited by the speed of the sink /dev/null, not a terminal.
slaxor.bash:
go build -o slaxor slaxor.go && time (for i in $(seq 10000) ; do ./slaxor 2> /dev/null ; done)
The benchmark measures the execution of a program and a single execution of the algorithm. The benchmark times are inconsistent because the pseudorandom seed value changes for each program execution. The benchmark sometimes "doesn't end even when I let it run for an hour or so."
There is a faster solution that runs and terminates in a few seconds, despite the program execution overhead.
peterso.bash:
go build -o peterso peterso.go && time (for i in $(seq 10000) ; do ./peterso 2> /dev/null ; done)
Output:
$ ./peterso.bash
real 0m5.290s
user 0m5.224s
sys 0m1.128s
$ ./peterso.bash
real 0m7.462s
user 0m7.109s
sys 0m1.922s
peterso.go:
package main
import (
"fmt"
"log"
"math/rand"
"time"
)
func main() {
seed := time.Now().UnixNano() & 999999999
log.Print("seed: ", seed)
r = rand.New(rand.NewSource(seed))
ordered := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
randomized := shufflePreventCollisionPeterSO(ordered)
log.Print("Final Result")
log.Print("ordered: ", ordered)
log.Print("random: ", randomized)
if randomized == nil {
err := "Shuffle Error!"
fmt.Print(err)
log.Fatal(err)
}
}
var r *rand.Rand
func isNoCollision(a, b []int) bool {
if len(a) == len(b) {
for i, ai := range a {
if ai == b[i] {
return false
}
}
return true
}
return false
}
func shufflePreventCollisionPeterSO(ordered []int) []int {
const guard = 4 * 1024 // deterministic, finite time
for n := 1; n <= guard; n++ {
randomized := r.Perm(len(ordered))
if isNoCollision(ordered, randomized) {
return randomized
}
}
return nil
}
The guard provides a deterministic, finite time, termination condition.
Playground: https://play.golang.org/p/ZT-sfDW5Mi
Let's put aside the distorted program execution benchmarks, let's look at function execution times. Because this is important, the Go standard library has the testing package for testing and benchmarking functions.
Tests:
$ go test shuffle_test.go -v -count=1 -run=. -bench=!
=== RUN TestTimeSlaxor
=== RUN TestTimeSlaxor/1K
=== RUN TestTimeSlaxor/2K
=== RUN TestTimeSlaxor/3K
--- PASS: TestTimeSlaxor (13.78s)
--- PASS: TestTimeSlaxor/1K (1.18s)
--- PASS: TestTimeSlaxor/2K (1.27s)
--- PASS: TestTimeSlaxor/3K (11.33s)
=== RUN TestTimePeterSO
=== RUN TestTimePeterSO/1K
=== RUN TestTimePeterSO/2K
=== RUN TestTimePeterSO/3K
=== RUN TestTimePeterSO/1M
=== RUN TestTimePeterSO/2M
=== RUN TestTimePeterSO/3M
--- PASS: TestTimePeterSO (6.57s)
--- PASS: TestTimePeterSO/1K (0.00s)
--- PASS: TestTimePeterSO/2K (0.00s)
--- PASS: TestTimePeterSO/3K (0.00s)
--- PASS: TestTimePeterSO/1M (1.13s)
--- PASS: TestTimePeterSO/2M (2.25s)
--- PASS: TestTimePeterSO/3M (3.19s)
PASS
ok command-line-arguments 20.347s
$
In a fraction of the rapidly increasing time it takes to run 3K (3,000) iterations of shufflePreventCollisionSlaxor, 3M (3,000,000) iterations of shufflePreventCollisionPeterSO run, a more than thousand-fold improvement.
Benchmarks:
$ go test shuffle_test.go -v -count=1 -run=! -bench=.
goos: linux
goarch: amd64
BenchmarkTimePeterSO-8 1000000 1048 ns/op 434 B/op 2 allocs/op
BenchmarkTimeSlaxor-8 10000 2256271 ns/op 636894 B/op 3980 allocs/op
PASS
ok command-line-arguments 23.643s
$
It's easy to see that the shufflePreventCollisionPeterSO average per iteration cost of 1,000,000 iterations is small, 1,048 nanoseconds, especially when compared to only 10,000 iterations of shufflePreventCollisionSlaxor at 2,256,271 nanoseconds average per iteration.
Also, note the sparing use of memory by shufflePreventCollisionPeterSO, on average 2 allocations for a total allocation of 434 bytes per iteration, versus the profligate use of memory by shufflePreventCollisionSlaxor, on average 3,980 allocations for a total allocation of 636,894 bytes per iteration.
shuffle_test.go:
package main
import (
"fmt"
"math/rand"
"strconv"
"testing"
)
func shufflePreventCollisionSlaxor(ordered []int) []int {
randomized := rand.Perm(len(ordered))
for i, o := range ordered {
if o == randomized[i] {
shufflePreventCollisionSlaxor(ordered)
}
}
return randomized
}
var r *rand.Rand
func isNoCollision(a, b []int) bool {
if len(a) == len(b) {
for i, ai := range a {
if ai == b[i] {
return false
}
}
return true
}
return false
}
func shufflePreventCollisionPeterSO(ordered []int) []int {
const guard = 4 * 1024 // deterministic, finite time
for n := 1; n <= guard; n++ {
randomized := r.Perm(len(ordered))
if isNoCollision(ordered, randomized) {
return randomized
}
}
return nil
}
const testSeed = int64(60309766)
func testTime(t *testing.T, ordered, randomized []int, shuffle func([]int) []int) {
shuffled := shuffle(ordered)
want := fmt.Sprintf("%v", randomized)
got := fmt.Sprintf("%v", shuffled)
if want != got {
t.Errorf("Error:\n from: %v\n want: %s\n got: %s\n", ordered, want, got)
}
}
func testTimeSlaxor(t *testing.T, n int) {
rand.Seed(testSeed)
ordered := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
randomized := []int{3, 1, 17, 15, 10, 16, 14, 19, 7, 6, 11, 2, 0, 12, 8, 18, 13, 4, 9, 5}
testTime(t, ordered, randomized, shufflePreventCollisionSlaxor)
for i := 1; i < n; i++ {
shufflePreventCollisionSlaxor(ordered)
}
}
func TestTimeSlaxor(t *testing.T) {
for k := 1; k <= 3; k++ {
n := 1000 * k
t.Run(strconv.Itoa(k)+"K", func(t *testing.T) { testTimeSlaxor(t, n) })
}
}
func testTimePeterSo(t *testing.T, n int) {
r = rand.New(rand.NewSource(testSeed))
ordered := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
randomized := []int{10, 7, 15, 14, 8, 6, 18, 17, 19, 11, 5, 16, 2, 12, 1, 13, 3, 0, 9, 4}
testTime(t, ordered, randomized, shufflePreventCollisionPeterSO)
for i := 1; i < n; i++ {
shufflePreventCollisionPeterSO(ordered)
}
}
func TestTimePeterSO(t *testing.T) {
for k := 1; k <= 3; k++ {
n := 1000 * k
t.Run(strconv.Itoa(k)+"K", func(t *testing.T) { testTimePeterSo(t, n) })
}
for m := 1; m <= 3; m++ {
n := 1000 * 1000 * m
t.Run(strconv.Itoa(m)+"M", func(t *testing.T) { testTimePeterSo(t, n) })
}
}
func benchTime(b *testing.B, ordered, randomized []int, shuffle func([]int) []int) {
shuffled := shuffle(ordered)
want := fmt.Sprintf("%v", randomized)
got := fmt.Sprintf("%v", shuffled)
if want != got {
b.Errorf("Error:\n from: %v\n want: %s\n got: %s\n", ordered, want, got)
}
}
func BenchmarkTimePeterSO(b *testing.B) {
b.ReportAllocs()
r = rand.New(rand.NewSource(testSeed))
ordered := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
randomized := []int{10, 7, 15, 14, 8, 6, 18, 17, 19, 11, 5, 16, 2, 12, 1, 13, 3, 0, 9, 4}
benchTime(b, ordered, randomized, shufflePreventCollisionPeterSO)
r = rand.New(rand.NewSource(testSeed))
b.ResetTimer()
for i := 0; i < b.N; i++ {
shufflePreventCollisionPeterSO(ordered)
}
}
func BenchmarkTimeSlaxor(b *testing.B) {
b.ReportAllocs()
r = rand.New(rand.NewSource(testSeed))
ordered := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
randomized := []int{10, 7, 15, 14, 8, 6, 18, 17, 19, 11, 5, 16, 2, 12, 1, 13, 3, 0, 9, 4}
benchTime(b, ordered, randomized, shufflePreventCollisionPeterSO)
r = rand.New(rand.NewSource(testSeed))
b.ResetTimer()
for i := 0; i < b.N; i++ {
shufflePreventCollisionSlaxor(ordered)
}
}
Playground: https://play.golang.org/p/ozazWGNZsu

Why is this so slow with goroutines?

I posted a question with nearly the same code yesterday, asking how to make this concurrent amongst a variadic function. After it was resolved, I expected the program to run nearly the same amount of time with one generator as with 30+. It doesn't seem so.
The times I see are with one generator, about 5ms. With what's in the code below, 150ms. (For some reason, play.golang shows 0).
Why is it slower? My expectation was that, with the multiple goroutines, it would take about as long. Something to do with spinning up the goroutines?
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
}
There is a little difference between go run and go build (compile time):
for me 17ms (on 2 Cores) and 3ms (on 8 Cores) with go1.7 amd64:
difference between go run and go build:
951.0543ms-934.0535ms = 17.0008ms (on 2 Cores)
575.3447ms-572.3914ms = 2.9533ms (on 8 Cores)
difference between 8 Cores and 2 Cores with go build:
934.0535ms-572.3914ms = 361.6621ms
For good benchmark statistics, use large number of samples.
try update to latest Go version ( 1.7).
Try this working sample code, and compare your result with these outputs:
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
}
output with 2 Cores ( with go run):
951.0543ms
len= 10000000
output with 2 Cores ( with go build):
934.0535ms
len= 10000000
output with 8 Cores ( with go run):
575.3447ms
len= 10000000
output with 8 Cores ( with go build):
572.3914ms
len= 10000000

Resources