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:
}
}
Related
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.
How to generate async function calls like in JS (you fire it and it goes to work independently)?
while(true)
{
if(s == "123")
//fire an async function to do some work and continue the cycle immediately
}
I do not need to wait, just start an average function with params to run when the system has time, but the cycle must not to be paused and waiting. It will run on Linux.
EDIT:
If I use it like this:
while(true)
{
if(s == "123")
std::future<std::string> resultFromDB = std::async(std::launch::async, fetchDataFromDB, "Data");
}
, will it be a problem, that resultFromDB gets another async assigned in each cycle run?
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
}
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.
I need to read UDP traffic until a timeout is reached. I can do this by calling SetDeadline on the UDPConn and looping until I get an I/O timeout error, but this seems hack-ish (flow control based on error conditions). The following code snippet seems more correct, but does not terminate. In production, this would obviously be executed in a goroutine; it's written as a main function for simplicity's sake.
package main
import (
"fmt"
"time"
)
func main() {
for {
select {
case <-time.After(time.Second * 1):
fmt.Printf("Finished listening.\n")
return
default:
fmt.Printf("Listening...\n")
//read from UDPConn here
}
}
}
Why doesn't the given program terminate? Based on https://gobyexample.com/select, https://gobyexample.com/timeouts, and https://gobyexample.com/non-blocking-channel-operations, I would expect the above code to select the default case for one second, then take the first case and break out of the loop. How might I modify the above snippet to achieve the desired effect of looping and reading until a timeout occurs?
If you are not concerned about read blocking past n seconds, then loop until the deadline:
deadline := time.Now().Add(n * time.Second)
for time.Now().Before(deadline) {
fmt.Printf("Listening...\n")
//read from UDPConn here
}
fmt.Printf("Finished listening.\n")
If you do want to break out of a blocking read after n seconds, then set a deadline and read until there's an error:
conn.SetReadDeadline(time.Now().Add(n * time.Second)
for {
n, err := conn.Read(buf)
if err != nil {
if e, ok := err.(net.Error); !ok || !e.Timeout() {
// handle error, it's not a timeout
}
break
}
// do something with packet here
}
Using a deadline is not hacky. The standard library uses deadlines while reading UDP connections (see the dns client).
There are alternatives to using a deadline to break a blocking read: close the connection or send a dummy packet that the reader recognizes. These alternatives require starting another goroutine and are much more complicated than setting a deadline.
Simply assign the channel from time.After outside the for loop, otherwise you will just create a new timer each time you loop.
Example:
func main() {
ch := time.After(time.Second * 1)
L:
for {
select {
case <-ch:
fmt.Printf("Finished listening.\n")
break L // have to use a label or it will just break select
default:
fmt.Printf("Listening...\n")
//read from UDPConn here
}
}
}
Note that this doesn't work on the playground.