i am trying to print concurrently but not able to figure out why its serial, have put the code below
package main
import (
"fmt"
"sync"
)
func main() {
fmt.Println("Hello, playground")
var wg sync.WaitGroup
wg.Add(2)
go func(){
for i := 0; i < 4; i++ {
if i%2 == 0 {
fmt.Println("hi", i)
}
}
wg.Done()
}()
go func() {
for i := 0; i < 4; i++ {
if i%2 != 0 {
fmt.Println("g", i)
}
}
wg.Done()
}()
wg.Wait()
}
expectation is
hi0
g1
hi2
g3
but i get
from g 1
from g 3
hi 0
hi 2
Such a small function is less likely to demonstrate the concurrency, because the first goroutine may complete even before the second one starts, or before context switch happens. If you add a small pause to the loop, you will observe the interleaving:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
wg.Add(2)
go func() {
for i := 0; i < 4; i++ {
if i%2 == 0 {
fmt.Println("hi", i)
}
time.Sleep(10 * time.Millisecond)
}
wg.Done()
}()
go func() {
for i := 0; i < 4; i++ {
if i%2 != 0 {
fmt.Println("from g", i)
}
time.Sleep(10 * time.Millisecond)
}
wg.Done()
}()
wg.Wait()
}
Related
I have the following program, I am new to gorountine, what I want to test is simple, I am calling a gorountine in a loop 100 times, it there is one time failure, the entire program fails, otherwise succeeds, and fail10Percent it delays 1 second, and check a random number if it is 4, let it fail.
package main
import (
"fmt"
"math/rand"
"time"
)
func fail10Percent(ch chan int) {
time.Sleep(1 * time.Second)
e := rand.Intn(10)
fmt.Println("Calculating rand.Intn(10) ", e)
if e == 4 {
ch <- 0
return
}
ch <- 1
}
func test() {
for i := 0; i < 100; i++ {
err := make(chan int)
go fail10Percent(err)
res := <-err
fmt.Println("=== result: ", res)
if res != 1 {
fmt.Println("failed")
return
}
}
fmt.Println("succeeded")
}
func main() {
test()
}
I expect the go fail10Percent(err) will run concurrently 100 times, which will only have 1 second delay, however, when I run it, I see the following result getting printed 1 second after 1 second, why is that, and how I can adjust my program to do what I want.
Calculating rand.Intn(10) 1
=== result: 1
Calculating rand.Intn(10) 7
=== result: 1
Calculating rand.Intn(10) 7
=== result: 1
Calculating rand.Intn(10) 9
=== result: 1
Calculating rand.Intn(10) 1
=== result: 1
Calculating rand.Intn(10) 8
=== result: 1
Calculating rand.Intn(10) 5
=== result: 1
Calculating rand.Intn(10) 0
=== result: 1
Calculating rand.Intn(10) 6
=== result: 1
Calculating rand.Intn(10) 0
=== result: 1
Calculating rand.Intn(10) 4
=== result: 0
failed
I've commented out the code for you so that you can understand.
package main
import (
"fmt"
"math/rand"
"sync"
)
func fail10Percent(ch chan int, w *sync.WaitGroup) {
defer w.Done()
num := rand.Intn(10)
fmt.Println("calculating rand.Intn(10) ", num)
if num == 4 {
ch <- 0 // Fail
return
}
ch <- 1 // Pass
}
func test() {
var ch = make(chan int, 1)
// Launch the receiver goroutine to listen if goroutine succeeded or failed based on the value sent to ch
go func() {
for recv := range ch {
switch recv {
// Fail
case 0:
fmt.Println("goroutine failed")
// Pass
case 1:
fmt.Println("goroutine succeed")
}
}
}()
// wg is a WaitGroup
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go fail10Percent(ch, &wg)
}
// wg.Wait() to wait for all goroutines to complete
wg.Wait()
// Close the channel so that the receiver can stop
close(ch)
}
func main() {
test()
}
Update:
Simple solution without using sync.WaitGroup
package main
import (
"fmt"
"math/rand"
)
// Using a send only channel
func fail10Percent(ch chan<- int) {
num := rand.Intn(10)
fmt.Println("calculating rand.Intn(10) ", num)
if num == 4 {
ch <- 0 // Fail
return
}
ch <- 1 // Pass
}
func test() {
var ch = make(chan int, 1)
for i := 0; i < 100; i++ {
go fail10Percent(ch)
}
for i := 0; i < 100; i++ {
if recv := <-ch; recv == 0 {
fmt.Println("goroutine failed")
} else if recv == 1 {
fmt.Println("goroutine succeed")
}
}
close(ch)
}
func main() {
test()
}
How to print numbers in order using goroutine after all goroutines bing emited?
Here is the code which print numbers in random:
func main() {
var wg sync.WaitGroup
wg.Add(10)
for i := 1; i <= 10; i++ {
go func(i int) {
defer wg.Done()
fmt.Printf("i = %d\n", i)
}(i)
}
wg.Wait()
Emit goroutines in order to print numbers like below, it's not the solution I want.
func main() {
var wg sync.WaitGroup
for i := 1; i <= 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
fmt.Printf("i = %d\n", i)
}(i)
wg.Wait()
}
I want all goroutines being emited, and after then make them print numbers in order.
func main() {
wg.Add(10)
count := 10
cBegins := make([]chan interface{}, count)
for i := range cBegins {
cBegins[i] = make(chan interface{})
}
go func() {
cBegins[0] <- struct {}{}
}()
for i := 0; i < count; i++ {
go func(i int) {
defer wg.Done()
<-cBegins[i]
fmt.Printf("i = %d\n", i)
if i < 9 {
cBegins[i+1] <- struct {}{}
}
}(i)
}
wg.Wait()
}
Why the result is not as expected with flag "-race" ?
It expected the same result: 1000000 - with flag "-race" and without this
https://gist.github.com/romanitalian/f403ceb6e492eaf6ba953cf67d5a22ff
package main
import (
"fmt"
"runtime"
"sync/atomic"
"time"
)
//$ go run -race main_atomic.go
//954203
//
//$ go run main_atomic.go
//1000000
type atomicCounter struct {
val int64
}
func (c *atomicCounter) Add(x int64) {
atomic.AddInt64(&c.val, x)
runtime.Gosched()
}
func (c *atomicCounter) Value() int64 {
return atomic.LoadInt64(&c.val)
}
func main() {
counter := atomicCounter{}
for i := 0; i < 100; i++ {
go func(no int) {
for i := 0; i < 10000; i++ {
counter.Add(1)
}
}(i)
}
time.Sleep(time.Second)
fmt.Println(counter.Value())
}
The reason why the result is not the same is because time.Sleep(time.Second) does not guarantee that all of your goroutines are going to be executed in the timespan of one second. Even if you execute go run main.go, it's not guaranteed that you will get the same result every time. You can test this out if you put time.Milisecond instead of time.Second, you will see much more inconsistent results.
Whatever value you put in the time.Sleep method, it does not guarantee that all of your goroutines will be executed, it just means that it's less likely that all of your goroutines won't finish in time.
For consistent results, you would want to synchronise your goroutines a bit. You can use WaitGroup or channels.
With WaitGroup:
//rest of the code above is the same
func main() {
counter := atomicCounter{}
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func(no int) {
for i := 0; i < 10000; i++ {
counter.Add(1)
}
wg.Done()
}(i)
}
wg.Wait()
fmt.Println(counter.Value())
}
With channels:
func main() {
valStream := make(chan int)
doneStream := make(chan int)
result := 0
for i := 0; i < 100; i++ {
go func() {
for i := 0; i < 10000; i++ {
valStream <- 1
}
doneStream <- 1
}()
}
go func() {
counter := 0
for count := range doneStream {
counter += count
if counter == 100 {
close(doneStream)
}
}
close(valStream)
}()
for val := range valStream {
result += val
}
fmt.Println(result)
}
I wrote a test code, but do not understand why I get this result.
My sub() should update or return counter, based on the channel value
send 1 = counter++
send 0 = return counter
I start 10 go routines con().
They should simply send many 1 to channel (this increase counter)
I wait 1 sec and send 0 to channel. What value should I get?
I think first, I get a "random" value,
but i get 100000 (ok 10x 10000 is faster than 1 sec)
Now I change
for i:=0; i < 10; i++ {
to
for i:=0; i < 10000; i++ {
and now my returned value is 1
Why!?
Now uncomment fmt.Println(counter) in main().
As you see counter works and has this "random" number
package main
import (
"fmt"
"time"
)
var ch chan int = make(chan int)
var counter int
func main() {
go sub()
for i:=0; i < 10; i++ { //change to 10000
go con()
}
time.Sleep(1000 * time.Millisecond)
ch <- 0
fmt.Println(<- ch)
//fmt.Println(counter) //uncomment this
}
func sub() {
for c := range ch {
if c == 0 { ch <- counter }
if c == 1 { counter++ }
}
}
func con() {
for i := 0; i < 10000; i++ {
ch <- 1
}
}
with 2 channels, this work:
package main
import (
"fmt"
"time"
)
var ch chan int = make(chan int)
var ch2 chan int = make(chan int)
var counter int
func main() {
go sub()
for i:=0; i < 10000; i++ { //change to 10000
go con()
}
time.Sleep(1000 * time.Millisecond)
ch2 <- 0
fmt.Println(<- ch2)
//fmt.Println(counter) //uncomment this
}
func sub() {
for ;; {
select {
case <- ch:
counter++
case <- ch2:
ch2 <- counter
}
}
}
func con() {
for i := 0; i < 10000; i++ {
ch <- 1
}
}
I am new to golang, and I am puzzled with this deadlock (run here)
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
c := make(chan string)
work := make(chan int, 1)
clvl := runtime.NumCPU()
count := 0
for i := 0; i < clvl; i++ {
go func(i int) {
for jdId := range work {
time.Sleep(time.Second * 1)
c <- fmt.Sprintf("done %d", jdId)
}
}(i)
}
go func() {
for i := 0; i < 10; i++ {
work <- i
}
close(work)
}()
for resp := range c {
fmt.Println(resp, count)
count += 1
}
}
You never close c, so your for range loop waits forever. Close it like this:
var wg sync.WaitGroup
for i := 0; i < clvl; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
for jdId := range work {
time.Sleep(time.Second * 1)
c <- fmt.Sprintf("done %d", jdId)
}
}(i)
}
go func() {
for i := 0; i < 10; i++ {
work <- i
}
close(work)
wg.Wait()
close(c)
}()
EDIT: Fixed the panic, thanks Crast