Issues with chans and waitgroups - go

While I've seen similar issues, none of the answers found on SO have helped me, but I hope a kind soul with an eagle eye can help me pinpoint the issue here. I know it's not the best use of goroutines but I wanted to do it this way as an exercise, which has obviously failed.
my code
package main
import (
"fmt"
"sort"
"sync"
)
func main() {
X := []int{1, 2, 3, 4, 0}
Y := []int{2, 3, 6, 8, 4}
solution := Solution(X, Y)
fmt.Println(solution)
}
//Solution solution
func Solution(X []int, Y []int) int {
size := len(X)
resultChan := make(chan int)
results := make(map[int]int)
ParseDivision(size, X, Y, resultChan)
for val := range resultChan {
results[val] = results[val] + 1
}
close(resultChan)
return FindGreatest(results)
}
//Divide divide
func Divide(a int, b int, resultChan chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
result := float64(a) / float64(b)
resultChan <- int(result * 1000)
}
//FindGreatest find greatest in map
func FindGreatest(myMap map[int]int) int {
values := make([]int, 0, len(myMap))
for _, val := range myMap {
values = append(values, val)
}
sort.Ints(values)
return values[len(values)-1]
}
//ParseDivision int
func ParseDivision(lenth int, X []int, Y []int, resultChan chan<- int) {
var wg sync.WaitGroup
wg.Add(lenth)
for i := 0; i < lenth; i++ {
go Divide(X[i], Y[i], resultChan, &wg)
}
wg.Wait()
}
Result: fatal error: all goroutines are asleep - deadlock!
I am not at all sure why as I've followed a number of examples as well as answers from SO, with respect to passing the waitGroup by reference, as well as using a channel to get the result of the operations performed in goroutines.

Some things to note:
the go-routine that writes to a channel should typically close the channel;
and following from above, the "reader" go-routine should wait for the channel to close (via range et.c) - i.e. it should never have to close the channel its reading from.
since your results channel is unbuffered (buffer size of 0), the main go-routine blocks waiting as the workers try to write, and the main go-routine is not (yet) reading from the results channel (as the pool manager go-routine must complete for this to happen - DEADLOCK!). Solution:
ensure the work pool go-routine runs independent of the main (reader) go-routine.
3-line fix: https://play.golang.org/p/9hYuyDgMjGi

Related

Go: transformed channel

Let's say I have an int channel in Go:
theint := make(chan int)
I want to wrap this channel in a new channel called incremented
incremented := make(chan int)
Such that:
go func() { theint <- 1 }
<- incremented // 2
appended can be assumed to be the only one that reads from the int.
It will work if a run a goroutine in the background
go func() {
for num := range theint {
incremented <- num + 1
}
}
However, I prefer to do it without a goroutine since I can't control it in my context.
Is there a simpler way to do it?
One thing that came to mind is python's yield:
for num in theint:
yield num + 1
Is something like this possible in go?
Generator pattern
What you are trying to implement is generator pattern. To use channels and goroutines for implementation of this pattern is totally common practice.
However, I prefer to do it without a goroutine since I can't control it in my context.
I believe the problem is deadlock
fatal error: all goroutines are asleep - deadlock!
To avoid deadlocks and orphaned (not closed) channels use sync.WaitGroup. This is an idiomatic way to control goroutines.
Playground
package main
import (
"fmt"
"sync"
)
func incGenerator(n []int) chan int {
ch := make(chan int)
var wg sync.WaitGroup
wg.Add(len(n))
for _, i := range n {
incremented := i + 1
go func() {
wg.Done()
ch <- incremented
}()
}
go func() {
wg.Wait()
close(ch)
}()
return ch
}
func main() {
n := []int{1, 2, 3, 4, 5}
for x := range incGenerator(n) {
fmt.Println(x)
}
}
One thing you can also consider is having a select on the int channel and an exit channel - in an infinite for loop. You can choose a variable increment value too. Please see code below:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var accum int //accumulator of incremented values
var wg sync.WaitGroup
c1 := make(chan int)
exChan := make(chan bool)
wg.Add(1)
go func() {
time.Sleep(time.Second * 1)
c1 <- 1
wg.Done()
}()
wg.Add(1)
go func() {
time.Sleep(time.Second * 2)
c1 <- 2
wg.Done()
}()
wg.Add(1)
go func() {
time.Sleep(time.Second * 2)
c1 <- 5
wg.Done()
}()
go func() {
wg.Wait()
close(exChan)
}()
for {
var done bool
select {
case incBy := <-c1: //Increment by value in channel
accum += incBy
fmt.Println("Received value to increment:", incBy, "; Accumulated value is", accum)
case d := <-exChan:
done = !(d)
}
if done == true {
break
}
}
fmt.Println("Final accumulated value is", accum)
}
Playground: https://play.golang.org/p/HmdRmMCN7U
Exit channel not needed, if we are having non-zero increments always. I like #I159 's approach too!
Anyways, hope this helps.

for loop causing deadlock

I have written some code example from GO Concurrency :
func gen(numbers ...int) <-chan int {
out := make(chan int)
go func() {
for _, number := range numbers {
out <- number
}
close(out)
}()
return out
}
func sq(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for number := range in {
out <- number * number
}
}()
return out
}
so I tried to use above code in my main function like this :
func main() {
result := sq(sq(sq(gen(1, 2, 3, 4))))
fmt.Println(<-result)
fmt.Println(<-result)
fmt.Println(<-result)
fmt.Println(<-result)
fmt.Println("-------------------")
for channelValue := range sq(sq(sq(gen(1, 2, 3, 4)))) {
fmt.Println(channelValue)
}
}
I was confused when I run the code I got this message after the loop:
fatal error: all goroutines are asleep - deadlock
Please help me to understand this. From what I understand is calling the fmt.Prinlnt(result) x 4 times is the same as the for loop on for channelValue := range sq(sq(sq(gen(1, 2, 3, 4)))). is this correct?
Could please tell me why I got deadlock after the loop?
The range over the channel blocks because the channel is not closed in sq.
func sq(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for number := range in {
out <- number * number
}
close(out)
}()
return out
}
A good way to debug deadlocks like this is to send the process a SIGQUIT. The runtime dumps the stacks of all the goroutines when a SIGQUIT is received. The stack dumps will often point to the issue.
You're not closing the out channel in the sq function
go func() {
for number := range in {
out <- number * number
}
close(out)
}()
https://play.golang.org/p/kk8-08SfwB

goroutines order of execution

I'm trying to understand this piece of code, not sure why the 2nd go is executed before the 1st one. It'd be great if someone can really help me out with this!
func sum(a []int, c chan int) {
fmt.Println("summing: ", a)
total := 0
for _, v := range a {
total += v
}
//fmt.Println("send to c",total)
c <- total // send total to c
}
func main() {
//a := []int{7, 2, 8,134,23,23,1,23,1234,143, -9, 4, 0, 1234}
c := make(chan int)
go sum([]int{1,2,3}, c)
go sum([]int{4,5,6}, c)
x := <-c
fmt.Println(x)
x = <-c
fmt.Println(x)
}
OUTPUT:
summing: [4 5 6]
15
summing: [1 2 3]
6
You have nothing explicitly synchronizing the order of the two goroutines. If you run this enough times, you will see the calls to fmt.Println print in different sequences. When executing goroutines, as they are concurrent operations, you have no guarantees when they will execute and/or complete. You need to use various standard library packages, or channels themselves to synchronize the execution of concurrently running goroutines.
For example (by leveraging the blocking nature of channels, you could do something like):
func main() {
c := make(chan int)
go sum([]int{1, 2, 3}, c)
//use the channel to block until it receives a send
x := <-c
fmt.Println(x)
//then execute the next routine
go sum([]int{4, 5, 6}, c)
x = <-c
fmt.Println(x)
}
Another example (significantly less practical, but here to look at other common go synchronization features) you could introduce a wait group, and a range over a channel:
func sum(a []int, c chan int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println("summing: ", a)
total := 0
for _, v := range a {
total += v
}
//fmt.Println("send to c",total)
c <- total // send total to c
}
func main() {
c := make(chan int)
wg := new(sync.WaitGroup)
//concurrently call the concurrent calls to sum, allowing execution to continue to the range of the channel
go func() {
//increment the wait group, and pass it to the sum func to decrement it when it is complete
wg.Add(1)
go sum([]int{1, 2, 3}, c, wg)
//wait for the above call to sum to complete
wg.Wait()
//and repeat...
wg.Add(1)
go sum([]int{4, 5, 6}, c, wg)
wg.Wait()
//all calls are complete, close the channel to allow the program to exit cleanly
close(c)
}()
//range of the channel
for theSum := range c {
x := theSum
fmt.Println(x)
}
}

Wait for a buffered channel to be full

I must have missed something because I haven't found the answer online for this pretty basic problem. I am using a buffered channel capable of holding three int values.
I am then using three goroutines to fill it up and I want to do an operation once the buffered channel is full.
Here is a snippet explaining the problem:
func main() {
// Initialization of the slice a and 0 < n < len(a) - 1.
difs := make(chan int, 3)
go routine(a[:n], difs)
go routine(a[n + 1:], difs)
go routine(a[n - 1:n + 1], difs)
fmt.Println(<-difs) // Display the first result returned by one of the routine.
}
func routine(a []int, out chan<- int) {
// Long computation.
out <- result
}
I would like to update my code so that fmt.Println(<-difs) displays an array of int when all the values have been computed. I could use three times <-difs but I wonder if Go offers something cleaner to do that.
Wait using channel itself, like this working sample code:
package main
import "fmt"
func main() {
a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} // Initialization of the slice a and 0 < n < len(a) - 1.
difs := make(chan int, 3)
go routine(a[0:4], difs)
go routine(a[4:8], difs)
go routine(a[8:12], difs)
result := []int{<-difs, <-difs, <-difs}
fmt.Println(result) // Display the first result returned by one of the routine.
}
func routine(a []int, out chan<- int) {
result := 0 // Long computation.
for _, v := range a {
result += v
}
out <- result
}
output:
[10 42 26]
The function len() supports channels, returning the number of unread queued elements within the channel. However, you'll have to run a loop to periodically check it.
The traditional method of handling this is using a sync.WaitGroup, as so:
func main() {
// Initialization of the slice a and 0 < n < len(a) - 1.
var wg sync.WaitGroup
wg.Add(3)
difs := make(chan int, 3)
go routine(a[:n], difs, &wg)
go routine(a[n + 1:], difs, &wg)
go routine(n - 1:n + 1], difs, &wg)
wg.Wait() // blocks until wg.Done() is called 3 times
fmt.Println(<-difs) // Display the first result returned by one of the routine.
}
// NOTE: This MUST accept a POINTER to the waitgroup. They are not copy-safe.
func routine(a []int, out chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
// Long computation.
out <- result
}

Slice append from channels

I want to create slice and add values returned from channel.
Below is the code I tried but could not able to solve it.
I have to send address of the slice, but I am not able to figure out how :(
package main
import "fmt"
import "time"
func sendvalues(cs chan int){
for i:=0;i<10;i++{
cs<-i
}
}
func appendInt(cs chan int, aINt []int)[]*int{
for {
select {
case i := <-cs:
aINt = append(aINt,i)//append returns new type right ?
fmt.Println("slice",aINt)
}
}
}
func main() {
cs := make(chan int)
intSlice := make([]int, 0,10)
fmt.Println("Before",intSlice)
go sendvalues(cs)
go appendInt(cs,intSlice)// I have to pass address here
time.Sleep(999*999999)
fmt.Println("After",intSlice)
}
Your code won't work for two (in fact three) reasons:
append returns a new slice as soon as the capacity is reached.
Thus, the assignment in appendInt will do nothing.
appendInt runs concurrently, therefore:
As long as appendInt does not message main that it is finished,
main does not know when the intSlice has all the values you want.
You have to wait for all goroutines to return at the end of main
Problem 1: Modifying slices in functions
You may know that in Go every value you pass to a function is copied. Reference values,
such as slices, are copied too, but have pointers internally which then point to the original memory location. That means you can modify the elements of a slice in a function. What you
can't do is reassigning this value with a new slice as the internal pointer would point to somewhere different. You need pointers for that. Example (Play):
func modify(s *[]int) {
for i:=0; i < 10; i++ {
*s = append(*s, i)
}
}
func main() {
s := []int{1,2,3}
modify(&s)
fmt.Println(s)
}
Problem 2: Synchronizing goroutines
To wait for started goroutines, you can use a sync.WaitGroup. Example (Play):
func modify(wg *sync.WaitGroup, s *[]int) {
defer wg.Done()
for i:=0; i < 10; i++ {
*s = append(*s, i)
}
}
func main() {
wg := &sync.WaitGroup{}
s := []int{1,2,3}
wg.Add(1)
go modify(wg, &s)
wg.Wait()
fmt.Println(s)
}
The example above waits (using wg.Wait()) for modify to finish
(modify calls wg.Done() when finished). If you remove the wg.Wait() call, you will
see why not synchronizing is a problem. Comparison of outputs:
With wg.Wait(): [1 2 3 0 1 2 3 4 5 6 7 8 9]
Without wg.Wait(): [1 2 3]
The main goroutine returns earlier than the modify goroutine which is why you will never
see the modified results. Therefore synchronizing is absolutely necessary.
A good way to communicate the new slice would be to use a channel. You would not need to
use pointers and you would have synchronization. Example (Play):
func modify(res chan []int) {
s := []int{}
for i:=0; i < 10; i++ {
s = append(s, i)
}
res <- s
}
func main() {
c := make(chan []int)
go modify(c)
s := <-c
fmt.Println(s)
}

Resources