self-training task - go

I need limit running function by maxTasks variable. Can you check my answer and possible to make adjustments.
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
maxTasks := 10
var tasks []func()
for x := 0; x < 50; x++ {
fmt.Println("add new task with num ", x)
tasks = append(tasks, func(x int) func() {
fmt.Println("create function with ", x)
return func() {
worktime := rand.Intn(10)
time.Sleep(time.Duration(worktime) * time.Second)
fmt.Println("current task:",x )
fmt.Println(" with worktime ",worktime)
}
}(x))
}
//tasks[0]()
ch := make(chan int, maxTasks)
for _, task := range tasks {
go func(t func()) {
ch <- 1
t()
fmt.Println("current task:",len(ch))
<- ch
}(task)
}
time.Sleep(10000 * time.Second)
}

Related

go concurrency prints serially

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

Attempt to parallelize not fast enough

I read about Go's concurrency model and also saw about the difference between concurrency and parallelism. In order to test parallel execution, I wrote the following program.
package main
import (
"fmt"
"runtime"
"time"
)
const count = 1e8
var buffer [count]int
func main() {
fmt.Println("GOMAXPROCS: ", runtime.GOMAXPROCS(0))
// Initialise with dummy value
for i := 0; i < count; i++ {
buffer[i] = 3
}
// Sequential operation
now := time.Now()
worker(0, count-1)
fmt.Println("sequential operation: ", time.Since(now))
// Attempt to parallelize
ch := make(chan int, 1)
now = time.Now()
go func() {
worker(0, (count/2)-1)
ch <- 1
}()
worker(count/2, count-1)
<-ch
fmt.Println("parallel operation: ", time.Since(now))
}
func worker(start int, end int) {
for i := start; i <= end; i++ {
task(i)
}
}
func task(index int) {
buffer[index] = 2 * buffer[index]
}
But the problem is: the results are not very pleasing.
GOMAXPROCS: 8
sequential operation: 206.85ms
parallel operation: 169.028ms
Using a goroutine does speed things up but not enough. I expected it to be closer to being twice as fast. What is wrong with my code and/or understanding? And how can I get closer to being twice as fast?
Parallelization is powerful, but it's hard to see with such a small computational load. Here is some sample code with a larger difference in the result:
package main
import (
"fmt"
"math"
"runtime"
"time"
)
func calctest(nCPU int) {
fmt.Println("Routines:", nCPU)
ch := make(chan float64, nCPU)
startTime := time.Now()
a := 0.0
b := 1.0
n := 100000.0
deltax := (b - a) / n
stepPerCPU := n / float64(nCPU)
for start := 0.0; start < n; {
stop := start + stepPerCPU
go f(start, stop, a, deltax, ch)
start = stop
}
integral := 0.0
for i := 0; i < nCPU; i++ {
integral += <-ch
}
fmt.Println(time.Now().Sub(startTime))
fmt.Println(deltax * integral)
}
func f(start, stop, a, deltax float64, ch chan float64) {
result := 0.0
for i := start; i < stop; i++ {
result += math.Sqrt(a + deltax*(i+0.5))
}
ch <- result
}
func main() {
nCPU := runtime.NumCPU()
calctest(nCPU)
fmt.Println("")
calctest(1)
}
This is the result I get:
Routines: 8
853.181µs
Routines: 1
2.031358ms

Closing and ranging over go channels

I'm new to Go and I am also kinda having a hard time reading the documentation. Can anyone help explain what is wrong with the code below
package main
import (
"fmt"
)
func main() {
c := make(chan int)
for i := 0; i < 10; i++ {
go func() {
add(c)
}()
}
close(c)
for v := range c {
fmt.Println(v)
}
}
func add(c chan<- int) {
c<-123
}
Based on the suggestion from icza :
package main
import (
"fmt"
"sync"
)
func main() {
c := make(chan int)
var wgConsumer sync.WaitGroup
wgConsumer.Add(1)
go func() {
defer wgConsumer.Done()
for v := range c {
fmt.Println(v)
}
}()
var wg sync.WaitGroup
wg.Add(10)
for i := 0; i < 10; i++ {
go func() {
add(c)
defer wg.Done()
}()
}
wg.Wait()
close(c)
wgConsumer.Wait()
}
func add(c chan<- int) {
c <- 123
}
Output:
123
123
123
123
123
123
123
123
123
123

what's wrong with the golang code by using ticker

package main
import (
"fmt"
"time"
)
func main() {
intChan := make(chan int, 1)
ticker := time.NewTicker(time.Second)
go func() {
for _ = range ticker.C {
select {
case intChan <- 1:
case intChan <- 2:
case intChan <- 3:
}
}
/*defer */
fmt.Println("End. [sender]")
}()
var sum int
for e := range intChan {
fmt.Printf("Received: %v\n", e)
sum += e
if sum > 10 {
fmt.Printf("Got: %v\n", sum)
break
//ticker.Stop()
}
}
fmt.Println("End. [receiver]")
//time.Sleep(10)
}
I'm new in golang. In this code, I want print "End. [sender]" once when the goroutine is over.
I try to use ticker.stop(), or even time.sleep(), defer , but no effect.
What's wrong with it, please give me some idea. thanks
As documentation says, ticker.Stop doesn't close channel. So you must not expect break-loop. You can add new channel for quit.
package main
import (
"fmt"
"time"
)
func main() {
intChan := make(chan int, 2)
ticker := time.NewTicker(time.Second)
quit := make(chan bool)
go func() {
loop:
for {
select {
case <-ticker.C:
select {
case intChan <- 1:
case intChan <- 2:
case intChan <- 3:
}
case <-quit:
break loop
}
}
/*defer */
fmt.Println("End. [sender]")
close(intChan)
}()
var sum int
for e := range intChan {
fmt.Printf("Received: %v\n", e)
sum += e
if sum > 10 {
fmt.Printf("Got: %v\n", sum)
quit <- true
//break
//ticker.Stop()
}
}
fmt.Println("End. [receiver]")
//time.Sleep(10)
}

go routine dead lock?

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

Resources