Ordering of senders in a Go channel - concurrency

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.

Related

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

Proper way to test a connection in go

I am covering project with tests and for that purpose I need dummy TCP Server, which could accept connection, write/read data to/from it, close it etc... I have found this question on stack overflow, covering mocking connection, but it doesn't cover what I actually need to test.
My idea relies on this article as starting point, but when I started implementing channel to let server write some data to newly opened connection, I got stuck with undebuggable deadlock in writing to channel.
What I want to achieve is to write some data to server's channel, say sendingQueue chan *[]byte, so later corresponding []byte will be sent to newly established connection.
During these little research I have tried debugging and printing out messages before/after sending data to channel and trying to send / read data from channel in different places of program.
What I found out:
My idea works if I add data directly in handleConnection with
go func() {
f := []byte("test.")
t.sendingQueue <- &f
}()
My idea doesn't work if I push data to channel from TestUtils_TestingTCPServer_WritesRequest in any form, either with func (t *TCPServer) Put(data *[]byte) (err error) or directly with:
go func(queue chan *[]byte, data *[]byte) {
queue <- data
}(t.sendingQueue, &payload)
It doesn't matter if channel is buffered or not.
So, obviously, there is something wrong either with the way I debug my code (I didn't dive into cli dlv, using just IDE debugger), or something that I completely miss about working with go channels, goroutines or net.Conn module.
For convenience public gist with full code is available. Note — there is // INIT part in the TestUtils_TestingTCPServer_WritesRequest which is required to run/debug single test. It should be commented out when running go test in the directory.
utils.go:
// NewServer creates a new Server using given protocol
// and addr.
func NewTestingTCPServer(protocol, addr string) (*TCPServer, error) {
switch strings.ToLower(protocol) {
case "tcp":
return &TCPServer{
addr: addr,
sendingQueue: make(chan *[]byte, 10),
}, nil
case "udp":
}
return nil, errors.New("invalid protocol given")
}
// TCPServer holds the structure of our TCP
// implementation.
type TCPServer struct {
addr string
server net.Listener
sendingQueue chan *[]byte
}
func (t *TCPServer) Run() (err error) {}
func (t *TCPServer) Close() (err error) {}
func (t *TCPServer) Put(data *[]byte) (err error) {}
func (t *TCPServer) handleConnection(conn net.Conn){
// <...>
// Putting data here successfully sends it via freshly established
// Connection:
// go func() {
// f := []byte("test.")
// t.sendingQueue <- &f
// }()
for {
fmt.Printf("Started for loop\n")
select {
case data := <-readerChannel:
fmt.Printf("Read written data\n")
writeBuffer.Write(*data)
writeBuffer.Flush()
case data := <-t.sendingQueue:
fmt.Printf("Read pushed data\n")
writeBuffer.Write(*data)
writeBuffer.Flush()
case <-ticker:
fmt.Printf("Tick\n")
return
}
fmt.Printf("Finished for loop\n")
}
}
utils_test.go
func TestUtils_TestingTCPServer_WritesRequest(t *testing.T) {
payload := []byte("hello world\n")
// <...> In gist here is placed INIT piece, which
// is required to debug single test
fmt.Printf("Putting payload into queue\n")
// This doesn't affect channel
err = utilTestingSrv.Put(&payload)
assert.Nil(t, err)
// This doesn't work either
//go func(queue chan *[]byte, data *[]byte) {
// queue <- data
//}(utilTestingSrv.sendingQueue, &payload)
conn, err := net.Dial("tcp", ":41123")
if !assert.Nil(t, err) {
t.Error("could not connect to server: ", err)
}
defer conn.Close()
out := make([]byte, 1024)
if _, err := conn.Read(out); assert.Nil(t, err) {
// Need to remove trailing byte 0xa from bytes array to make sure bytes array are equal.
if out[len(payload)] == 0xa {
out[len(payload)] = 0x0
}
assert.Equal(t, payload, bytes.Trim(out, "\x00"))
} else {
t.Error("could not read from connection")
}
}
After a help from a colleague and reading the article on how init works, I found a problem.
It was in init function, which was recreating extra server, due to using := assignment. I also updated code to make sure server runs before net.Dial and conn.Read.

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

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
}

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:
}
}

How do I read a UDP connection until a timeout is reached?

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.