Why does my concurrent function exit prematurely in Go? [duplicate] - concurrency

This question already has answers here:
No output from goroutine
(3 answers)
Closed 6 years ago.
I am looking through Go Bootcamp and am reading the Go Concurrency chapter right now. I have never used concurrency before in programming and don't understand the output of this program:
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 2; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world")
say("hello")
}
Output:
hello
world
hello
Program exited.
Can someone explain why "world" is not printed twice like "hello"? And maybe elucidate the idea of using concurrency?
Note, Go Playground link here.

A Go program exits when main returns. In this case, your program is not waiting for the final "world" to be printed in another goroutine before exiting.
The following code (playground) will ensure main never exits allowing the other goroutine to finish.
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 2; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world")
say("hello")
select{}
}
As you may have noticed, this results in a deadlock because the program has no way to go forward. You may wish to add a channel or a sync.Waitgroup to ensure the program exits cleanly immediately after the other goroutine completes.
For example (playground):
func say(s string, ch chan<- bool) {
for i := 0; i < 2; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
if ch != nil {
close(ch)
}
}
func main() {
ch := make(chan bool)
go say("world", ch)
say("hello", nil)
// wait for a signal that the other goroutine is done
<-ch
}

Related

Why does benbjohnson/clock mock timer not execute when declared inside a goroutine?

This code works as I expect it
import (
"fmt"
"time"
"github.com/benbjohnson/clock"
)
func main() {
mockClock := clock.NewMock()
timer := mockClock.Timer(time.Duration(2) * time.Second)
go func() {
<-timer.C
fmt.Println("Done")
}()
mockClock.Add(time.Duration(10) * time.Second)
time.Sleep(1)
}
It prints "Done" as I expect.
Whereas this function does not
import (
"fmt"
"time"
"github.com/benbjohnson/clock"
)
func main() {
mockClock := clock.NewMock()
go func() {
timer := mockClock.Timer(time.Duration(2) * time.Second)
<-timer.C
fmt.Println("Done")
}()
mockClock.Add(time.Duration(10) * time.Second)
time.Sleep(1)
}
The only difference here is I'm declaring the timer outside the goroutine vs. inside it. The mockClock Timer() method has a pointer receiver and returns a pointer. I can't explain why the first one works and the second doesn't.
The package benbjohnson/clock provides mock time facilities. In particular their documentation states:
Timers and Tickers are also controlled by this same mock clock. They will only execute when the clock is moved forward
So when you call mockClock.Add, it will sequentially execute the timers/tickers. The library also adds sequential 1 millisecond sleeps to artificially yield to other goroutines.
When the timer/ticker is declared outside the goroutine, i.e. before calling mockClock.Add, by the time mockClock.Add gets called the mock time does have something to execute. The library's internal sleeps are enough for the child goroutine to receive on the ticker and print "done", before the program exits.
When the ticker is declared inside the goroutine, by the time mockClock.Add gets called, the mock time has no tickers to execute and Add essentially does nothing. The internal sleeps do give a chance to the child goroutine to run, but receiving on the ticker now just blocks; main then resumes and exits.
You can also have a look at the ticker example that you can see in the repository's README:
mock := clock.NewMock()
count := 0
// Kick off a timer to increment every 1 mock second.
go func() {
ticker := mock.Ticker(1 * time.Second)
for {
<-ticker.C
count++
}
}()
runtime.Gosched()
// Move the clock forward 10 seconds.
mock.Add(10 * time.Second)
// This prints 10.
fmt.Println(count)
This uses runtime.Gosched() to yield to the child goroutine before calling mock.Add. The sequence of this program is basically:
clock.NewMock()
count := 0
spawn child goroutine
runtime.Gosched(), yielding to the child goroutine
ticker := mock.Ticker(1 * time.Second)
block on <-ticker.C (the mock clock hasn't moved forward yet)
resume main
mock.Add, which moves the clock forward and yields to the child goroutine again
for loop with <-ticker.C
print 10
exit
By the same logic, if you add a runtime.Gosched() to your second snippet, it will work as expected, just like the repository's example. Playground: https://go.dev/play/p/ZitEdtx9GdL
However, do not rely on runtime.Gosched() in production code, possibly not even in test code, unless you're very sure about what you are doing.
Finally, please remember that time.Sleep(1) sleeps for one nanosecond.

Golang read constant data from TCP Port [duplicate]

This question already has an answer here:
Does ReadString() discard bytes following newline?
(1 answer)
Closed 2 years ago.
I've have a process that spits out data to a TCP port in bursts with a few minutes pause between files. I've tried the code below that I've seen on multiple different posts however a large amount (multiple lines worth) of data is lost from the output. I've also tried writing similar code in C++ with the same result. The only reliable way I've found to get all output is to just listen using nc but I would like to do this programmatically so that I can use the downtime between bursts in order to separate output into multiple files. Has anyone ran into this issue before? I don't see any pattern to the missing data, just as if some random lines are getting skipped. I even tried to just send the data to a go chan, to see if the print statement was slowing down execution somehow. Any help would be appreciated!
package main
import (
"bufio"
"fmt"
"net"
"os"
)
func main() {
arguments := os.Args
if len(arguments) == 1 {
fmt.Println("Please provide host:port.")
return
}
CONNECT := arguments[1]
c, err := net.Dial("tcp", CONNECT)
if err != nil {
fmt.Println(err)
return
}
for {
message, _ := bufio.NewReader(c).ReadString('\n')
fmt.Print(message)
}
}
Unfortunately I can not mark comments as answers, however as Cerise Limón pointed out- using a bufio.Scanner() was the solution. The functional code is below. Thank you!
package main
import (
"bufio"
"fmt"
"net"
"os"
)
func main() {
arguments := os.Args
if len(arguments) == 1 {
fmt.Println("Please provide host:port.")
return
}
CONNECT := arguments[1]
c, err := net.Dial("tcp", CONNECT)
if err != nil {
fmt.Println(err)
return
}
scanner := bufio.NewScanner(c) // Declare outside of the loop
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}

How to Close the goroutine which waiting on I/O

I have created two go routines sender and receiver, sender will continuous get the data from the user(keyboard) and write to stream, receiver will independently get the value from stream print it to the screen. Both are concurrent using go routine
At some point of time receiver failed and close the connection as well as exit the receiver go routine, but sender go routine which waiting for user input(i/o operation) will not be closed. How to exit all the go routines in this scenario?
Below is the piece of sample code for this scenario.
package main
import (
"fmt"
"time"
)
var stop bool = false
func sender() {
str := ""
for !stop {
fmt.Scanf("%s", &str)
fmt.Println("Entered :", str)
}
fmt.Println("Closing sender goroutine")
}
func receiver() {
i := 0
for !stop {
i++
if i > 5 {
stop = true
}
time.Sleep(1 * time.Second)
}
fmt.Println("Closing receiver goroutine")
}
func main() {
go sender()
go receiver()
/* Wait for goroutines to finish */
for !stop {
time.Sleep(1 * time.Millisecond)
}
time.Sleep(1 * time.Second)
panic("Display stack")
}
Above code sender will wait for user input after 5 loop receiver will exit the receiver go routine. I expect when receiver close, go routine which waiting on i/o has to be closed.
Kindly help me on this question.
As Dave C & JimB say, use channels to coordinate goroutines. Here's an example that may help.
Exit after receiving 5 messages from the user:
package main
import "fmt"
var pipe = make(chan string) //shares text entered by user
var stop = make(chan bool) //shares stop signal
func listen() {
for {
var input string
fmt.Scan(&input)
pipe <- input
}
}
func write() {
for i := 0; i < 5; i++ {
var output string
output = <-pipe
fmt.Println("Received", output)
}
stop <- true
}
func main() {
go listen()
go write()
<-stop
}
To start, your code has a race around the stop variable. When there's a data race, there's no guarantee your program will behave as defined. Use channels to synchronize goroutines. This however isn't why you program continues.
Your code is blocking on fmt.Scanf, and doesn't get to check the stop condition. Since a Read on Stdin can't be interrupted (which is happening inside fmt.Scanf), you need to check for the stop condition before calling Scanfagain. If there's no more input, but you have a pending Read on Stdin, the easiest way to handle it is to just let leave that goroutine running. There are some rather complex ways to break out of this using something known as the "self-pipe" trick, but it's generally not worth the effort, as goroutines are small and don't take many resources.
for {
fmt.Scanf("%s", &str)
fmt.Println("Entered :", str)
// use a channel or context to detect when to exit
select {
case <-ctx.Done():
return
default:
}
}

Ordering of senders in a Go channel

Consider the ping pong example from http://www.golang-book.com/10/index.htm#section2.
package main
import (
"fmt"
"time"
)
func pinger(c chan string) {
for i := 0; ; i++ {
c <- "ping"
}
}
func ponger(c chan string) {
for i := 0; ; i++ {
c <- "pong"
}
}
func printer(c chan string) {
for {
msg := <- c
fmt.Println(msg)
time.Sleep(time.Second * 1)
}
}
func main() {
var c chan string = make(chan string)
go pinger(c)
go ponger(c)
go printer(c)
var input string
fmt.Scanln(&input)
}
The authors write:
"The program will now take turns printing ping and pong."
However, for this to be true, Go must decide on an order in which senders can send into a channel? Otherwise, there would be no guarantee that a ping would be sent before a pong (i.e. you can't get two pings, or two pongs in a row). How does this work?
There is no synchronization between the ping and pong goroutines, therefore there is no guarantee that the responses will print in order.
If you force the goroutines to race with GOMAXPROCS>1, you get random output:
pong
ping
ping
pong
ping
pong
ping
pong
pong
This isn't even an example of a "ping-pong", since there's is no call and response.
There was a related question on the order of selection of messages entering a channel recently.
The answer is that the order is normally non-deterministic. This is intentional.

Testing Goroutine That My Code Does Not Wait For

I have a function that is executed concurrently. It's task is to run a command line method, logging an error if there is one. My main thread of execution does not wait for this method to finish. It simply returns optimistically.
How do I test my function? Assuming that I give it a cmdStr, such as {"sleep", "1"}, that works but doesn't return instantly, how can I get my test to wait for this function to finish?
I want to ensure that the actual program that runs this does not have to wait for it to finish.
func runCmd(cmdStr []string, errChan chan error) {
cmd := exec.Command(cmdStr...)
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Start()
if err != nil {
errChan <- err
return
}
// Command started successfully, so our caller can continue.
errChan <- nil
err = cmd.Wait()
if err != nil {
log.Println(err)
}
}
Use a wait group
wg := sync.WaitGroup{}
errc := make(chan error)
wg.Add(1)
go func() {
runCmd([]string{"sleep", 1}, errc)
wg.Done()
}()
err <- errc
if err != nil {
// handle error
}
wg.Wait()
Simplest method to aware all goroutings done is to add select{} as last main.main() statement. But main() will never return this way and you should kill process explicitly.
It's also more gentle runtime.Goshed() to wait for others, but it can't provide such a strong guarantee.
And the canonical way would be
wg := sync.WaitGroup
...
wg.Add(1)
go runCmd(...)
...
wg.Wait()