This question already has answers here:
Why does fmt.Println inside a goroutine not print a line?
(4 answers)
why doesn't this go code print anything with a goroutine [duplicate]
(2 answers)
Closed 8 years ago.
I'm recently looking into Golang by google and I met with the following problem. Then program doesn't print anything. But if I remove the "go" notations, it will print both "goroutine" and "going".
package main
import "fmt"
func f(msg string) {
fmt.Println(msg)
return
}
func main() {
go f("goroutine")
go func(msg string) {
fmt.Println(msg)
return
}("going")
return
}
You program exits before the goroutines is executed. You could wait a little bit, for example by calling time.Sleep(2 * time.Second), but such behaviour is considered bad practice, since your program could run longer than 2 seconds and would then terminate nonetheless.
A better approach is to use sync.WaitGroup:
package main
import (
"fmt"
"sync"
)
func f(msg string, wg *sync.WaitGroup) {
fmt.Println(msg)
wg.Done()
}
func main() {
var wg sync.WaitGroup
wg.Add(1)
go f("goroutine", &wg)
wg.Add(1)
go func(msg string) {
fmt.Println(msg)
wg.Done()
}("going")
wg.Wait()
}
Your code needs to wait for the routines to finish before exiting. A good way to do this is to pass in a channel which is used by the routine to signal when it's done and then wait in the main code. See below.
Another advantage of this approach is that it allows/encourages you to perform proper error handling based on the return value.
package main
import (
"fmt"
)
func f(msg string, quit chan int) {
fmt.Println(msg)
quit <- 0
return
}
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go f("goroutine", ch1)
go func(msg string, quit chan int) {
fmt.Println(msg)
quit <- 0
return
}("going", ch2)
<-ch1
<-ch2
return
}
Related
This question already has answers here:
How to test a function's output (stdout/stderr) in unit tests
(3 answers)
Closed 3 years ago.
I work on a small CLI application. I am trying to write unit tests. I have a function that renders some output as a table to the command line using fmt.Println/fmt.Printf. I am wondering how I can capture that output in a unit test to make sure I am getting what is expected? Below is just a barebone skeleton that somewhat represents what I am trying to achieve.
main.go
package main
import (
"fmt"
"io"
)
func print() {
fmt.Println("Hello world")
}
func main() {
print()
}
main_test.go
package main
import "testing"
func TestPrint(t *testing.T) {
expected := "Hello world"
print() // somehow capture the output
// if got != expected {
// t.Errorf("Does not match")
// }
}
I have tried a few approaches such as How to check a log/output in go test? but with minimal luck but, that could be due to misunderstanding on my end.
you got to inject, somehow, the destination writer.
Your API is insufficient because it does not allow injection.
In this modified code, the destination writer is given as an argument, but other API implementation decision are possible.
package main
import (
"fmt"
"io"
)
func print(dst io.Writer) {
fmt.Fprintln(dst, "Hello world")
}
func main() {
print(os.Stdout)
}
you can test doing so
package main
import "testing"
func TestPrint(t *testing.T) {
expected := "Hello world"
var b bytes.Buffer
print(&b) // somehow capture the output
// if b.String() != expected {
// t.Errorf("Does not match")
// }
}
bytes.Buffer implements io.Writer and can be used as a stub to capture execution results.
https://golang.org/pkg/bytes/#Buffer
New to go. I'm using 1.5.1. I'm trying to accumulate a word list based on an incoming channel. However, my input channel (wdCh) is sometimes getting the empty string ("") during testing. I'm perplexed. I'd rather not have a test for the empty string before I add its accumulated count in my map. Feels like a hack to me.
package accumulator
import (
"fmt"
"github.com/stretchr/testify/assert"
"testing"
)
var words map[string]int
func Accumulate(wdCh chan string, closeCh chan bool) {
words = make(map[string]int)
for {
select {
case word := <-wdCh:
fmt.Printf("word = %s\n", word)
words[word]++
case <-closeCh:
return
}
}
}
func pushWords(w []string, wdCh chan string) {
for _, value := range w {
fmt.Printf("sending word = %s\n", value)
wdCh <- value
}
close(wdCh)
}
func TestAccumulate(t *testing.T) {
sendWords := []string{"one", "two", "three", "two"}
wMap := make(map[string]int)
wMap["one"] = 1
wMap["two"] = 2
wMap["three"] = 1
wdCh := make(chan string)
closeCh := make(chan bool)
go Accumulate(wdCh, closeCh)
pushWords(sendWords, wdCh)
closeCh <- true
close(closeCh)
assert.Equal(t, wMap, words)
}
Check out this article about channel-axioms. Looks like there's a race between closing wdCh and sending true on the closeCh channel.
So the outcome depends on what gets scheduled first between pushWords returning and Accumulate.
If TestAccumulate runs first, sending true on closeCh, then when Accumulate runs it picks either of the two channels since they can both be run because pushWords closed wdCh.
A receive from a closed channel returns the zero value immediately.
Until closedCh is signaled, Accumulate will randomly put one or more empty "" words in the map.
If Accumulate runs first then it's likely to put many empty strings in the word map as it loops until TestAccumulate runs and finally it sends a signal on closeCh.
An easy fix would be to move
close(wdCh)
after sending true on the closeCh. That way wdCh can't return the zero value until after you've signaled on the closeCh. Additionally, closeCh <- true blocks because closeCh doesn't have a buffer size, so wdCh won't get closed until after you've guaranteed that Accumulate has finished looping forever.
I think the reason is when you close the channle, "select" will although receive the signal.
So when you close "wdCh" in "func pushWords", the loop in Accumulate will receive signal from "<-wdCh".
May be you should add some code to test the action after channel is closed!
for {
select {
case word, ok := <-wdCh:
if !ok {
fmt.Println("channel wdCh is closed!")
continue
}
fmt.Printf("word = %s\n", word)
words[word]++
case <-closeCh:
return
}
}
I am running the following go code and it doesn't produce output:
package main
import "fmt"
//import "strconv"
import "time"
func Wait(){
time.Sleep(2000 * time.Millisecond)
}
func Print(c chan string){
fmt.Println("Running Print go-routine")
for{
fmt.Println("len(c): ", len(c))
str := <- c
fmt.Println(str)
}
}
func main() {
c := make(chan string, 4)
c <- "0"
c <- "1"
c <- "2"
c <- "3"
Wait()
fmt.Println("Before go Print(c)")
go Print(c)
fmt.Println("After go Print(c)")
}
Is there a deadlock? The Print(c) function is not even called...? Its very strange to me.
The link to it in go playground is: http://play.golang.org/p/tDjEJKwkRJ
There isn't an error, the Print() function is called in a goroutine, but the main program is exiting right after that... so the goroutine is terminated.
Read this talk: Go Concurrency Patterns (or better, view it's video), to understand how channels and goroutines work.
Keep in mind that the program is finished when the main function returns.
When the main function invocation returns, the program exits. It does not wait for other (non-main) goroutines to complete.
Call your Wait function later, after the go Print(c) statement. For example,
package main
import (
"fmt"
"time"
)
func Wait() {
time.Sleep(2000 * time.Millisecond)
}
func Print(c chan string) {
fmt.Println("Running Print go-routine")
for {
fmt.Println("len(c): ", len(c))
str := <-c
fmt.Println(str)
}
}
func main() {
c := make(chan string, 4)
c <- "0"
c <- "1"
c <- "2"
c <- "3"
fmt.Println("Before go Print(c)")
go Print(c)
Wait()
fmt.Println("After go Print(c)")
}
Output:
Before go Print(c)
Running Print go-routine
len(c): 4
0
len(c): 3
1
len(c): 2
2
len(c): 1
3
len(c): 0
After go Print(c)
The Go Programming Language Specification
Program execution
A complete program is created by linking a single, unimported package
called the main package with all the packages it imports,
transitively. The main package must have package name main and declare
a function main that takes no arguments and returns no value.
func main() { … }
Program execution begins by initializing the main package and then
invoking the function main. When that function invocation returns, the
program exits. It does not wait for other (non-main) goroutines to
complete.
I'm trying to implement a pool of workers in Go. The go-wiki (and Effective Go in the Channels section) feature excellent examples of bounding resource use. Simply make a channel with a buffer that's as large as the worker pool. Then fill that channel with workers, and send them back into the channel when they're done. Receiving from the channel blocks until a worker is available. So the channel and a loop is the entire implementation -- very cool!
Alternatively one could block on sending into the channel, but same idea.
My question is about changing the size of the worker pool while it's running. I don't believe there's a way to change the size of a channel. I have some ideas, but most of them seem way too complicated. This page actually implements a semaphore using a channel and empty structs in much the same way, but it has the same problem (these things come up all the time while Googling for "golang semaphore".
I would do it the other way round. Instead of spawning many goroutines (which still require a considerable amount of memory) and use a channel to block them, I would model the workers as goroutines and use a channel to distribute the work. Something like this:
package main
import (
"fmt"
"sync"
)
type Task string
func worker(tasks <-chan Task, quit <-chan bool, wg *sync.WaitGroup) {
defer wg.Done()
for {
select {
case task, ok := <-tasks:
if !ok {
return
}
fmt.Println("processing task", task)
case <-quit:
return
}
}
}
func main() {
tasks := make(chan Task, 128)
quit := make(chan bool)
var wg sync.WaitGroup
// spawn 5 workers
for i := 0; i < 5; i++ {
wg.Add(1)
go worker(tasks, quit, &wg)
}
// distribute some tasks
tasks <- Task("foo")
tasks <- Task("bar")
// remove two workers
quit <- true
quit <- true
// add three more workers
for i := 0; i < 3; i++ {
wg.Add(1)
go worker(tasks, quit, &wg)
}
// distribute more tasks
for i := 0; i < 20; i++ {
tasks <- Task(fmt.Sprintf("additional_%d", i+1))
}
// end of tasks. the workers should quit afterwards
close(tasks)
// use "close(quit)", if you do not want to wait for the remaining tasks
// wait for all workers to shut down properly
wg.Wait()
}
It might be a good idea to create a separate WorkerPool type with some convenient methods. Also, instead of type Task string it is quite common to use a struct that also contains a done channel that is used to signal that the task had been executed successfully.
Edit: I've played around a bit more and came up with the following: http://play.golang.org/p/VlEirPRk8V. It's basically the same example, with a nicer API.
A simple change that can think is to have a channel that controls how big is the semaphore.
The relevant part is the select statements. If there is more work from the queue process it with the current semaphore. If there is a request to change the size of the semaphore change it and continue processing the req queue with the new semaphore. Note that the old one is going to be garbage collected.
package main
import "time"
import "fmt"
type Request struct{ num int }
var quit chan struct{} = make(chan struct{})
func Serve(queue chan *Request, resize chan int, semsize int) {
for {
sem := make(chan struct{}, semsize)
var req *Request
select {
case semsize = <-resize:
{
sem = make(chan struct{}, semsize)
fmt.Println("changing semaphore size to ", semsize)
}
case req = <-queue:
{
sem <- struct{}{} // Block until there's capacity to process a request.
go handle(req, sem) // Don't wait for handle to finish.
}
case <-quit:
return
}
}
}
func process(r *Request) {
fmt.Println("Handled Request", r.num)
}
func handle(r *Request, sem chan struct{}) {
process(r) // May take a long time & use a lot of memory or CPU
<-sem // Done; enable next request to run.
}
func main() {
workq := make(chan *Request, 1)
ctrlq := make(chan int)
go func() {
for i := 0; i < 20; i += 1 {
<-time.After(100 * time.Millisecond)
workq <- &Request{i}
}
<-time.After(500 * time.Millisecond)
quit <- struct{}{}
}()
go func() {
<-time.After(500 * time.Millisecond)
ctrlq <- 10
}()
Serve(workq, ctrlq, 1)
}
http://play.golang.org/p/AHOLlAv2LH
I'm writing a function where I'm trying to increment a channel. In a much larger program, this is not working and it actually hangs on a line that looks like:
current = <-channel
The go funcs are running, but the program seems to halt on this line.
I tried to write a smaller SSCCE, but now I'm having a different problem. Here it is:
package main
import (
"fmt"
)
func main() {
count := make(chan int)
go func(count chan int) {
current := 0
for {
current = <-count
current++
count <- current
fmt.Println(count)
}
}(count)
}
However, in the above the go func does not actually seem to be called at all. If I put a fmt.Println statement before for {, it does not print out. If I put fmt.Println statements before or after they go func block, they will both print out.
Why does the self-calling block in the above example not seem to run at all?
If it were running, why would it block on current = <-count? How could I properly increment the channel?
I can't answer the first one issue without more info. The code you did show has two issues. First, the program exits after the goroutine is started. The second issue is that the goroutine is waiting for something to be sent to count, if you receive from the count channel it will not deadlock.
Here is an example showing the deadlock (http://play.golang.org/p/cRgjZt7U2A):
package main
import (
"fmt"
)
func main() {
count := make(chan int)
go func() {
current := 0
for {
current = <-count
current++
count <- current
fmt.Println(count)
}
}()
fmt.Println(<-count)
}
Here is an example of it working the way I think you are expecting (http://play.golang.org/p/QQnRpCDODu)
package main
import (
"fmt"
)
func main() {
count := make(chan int)
go func() {
current := 0
for {
current = <-count
current++
count <- current
fmt.Println(count)
}
}()
count <- 1
fmt.Println(<-count)
}
Channel :- Channel is something that can't store the value. It can only buffer the value so the basic usage is it can send and receive the value. So when you declare count := make(chan int) it does not contain any value. So the statement current = <-count will give you error that all go routines are asleep. Basically channel was design to work as communicator for different go routines which are running on different process and your main function is running on different process.
So your answer to first question is:-
1.Why does the self-calling block in the above example not seem to run at all?
Answer- See the main function you are running has one process and the go routine is running on another process so if your main function gets its execution completed before your go-routine than you will never get result form go-routine because your main thread gets dead after the execution is complete. So i am providing you a web example which is related to your example of incrementing the counter. In this example you will create a server and listen on port 8000.First of all run this example and go in your web browser and type localhost:8000 and it will so you the incrementing counter that channel stores in every buffer. This example will provide you an idea of how channel works.
2.If it were running, why would it block on current = <-count? How could I properly increment the channel?
Answer-You are receiving from the channel but channel does not have anything in its buffer so you will get an error "All go-routines are asleep". First you should transfer value into the channel and correspondingly receive it otherwise it will again go to deadlock.
package main
import (
"fmt"
"http"
)
type webCounter struct {
count chan int
}
func NewCounter() *webCounter {
counter := new(webCounter)
counter.count = make(chan int, 1)
go func() {
for i:=1 ;; i++ { counter.count <- i }
}()
return counter
}
func (w *webCounter) ServeHTTP(r http.ResponseWriter, rq *http.Request) {
if rq.URL.Path != "/" {
r.WriteHeader(http.StatusNotFound)
return
}
fmt.Fprintf(r, "You are visitor %d", <-w.count)
}
func main() {
http.ListenAndServe(":8000", NewCounter());
}