Asked  7 Months ago    Answers:  5   Viewed   31 times

While SayHello() executes as expected, the goroutine prints nothing.

package main

import "fmt"

func SayHello() {
    for i := 0; i < 10 ; i++ {
        fmt.Print(i, " ")
    }
}

func main() {
    SayHello()
    go SayHello()
}

 Answers

65

When your main() function ends, your program ends as well. It does not wait for other goroutines to finish.

Quoting from the Go Language Specification: Program Execution:

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.

See this answer for more details.

You have to tell your main() function to wait for the SayHello() function started as a goroutine to complete. You can synchronize them with channels for example:

func SayHello(done chan int) {
    for i := 0; i < 10; i++ {
        fmt.Print(i, " ")
    }
    if done != nil {
        done <- 0 // Signal that we're done
    }
}

func main() {
    SayHello(nil) // Passing nil: we don't want notification here
    done := make(chan int)
    go SayHello(done)
    <-done // Wait until done signal arrives
}

Another alternative is to signal the completion by closing the channel:

func SayHello(done chan struct{}) {
    for i := 0; i < 10; i++ {
        fmt.Print(i, " ")
    }
    if done != nil {
        close(done) // Signal that we're done
    }
}

func main() {
    SayHello(nil) // Passing nil: we don't want notification here
    done := make(chan struct{})
    go SayHello(done)
    <-done // A receive from a closed channel returns the zero value immediately
}

Notes:

According to your edits/comments: if you want the 2 running SayHello() functions to print "mixed" numbers randomly: you have no guarantee to observe such behaviour. Again, see the aforementioned answer for more details. The Go Memory Model only guarantees that certain events happen before other events, you have no guarantee how 2 concurrent goroutines are executed.

You might experiment with it, but know that the result will not be deterministic. First you have to enable multiple active goroutines to be executed with:

runtime.GOMAXPROCS(2)

And second you have to first start SayHello() as a goroutine because your current code first executes SayHello() in the main goroutine and only once it finished starts the other one:

runtime.GOMAXPROCS(2)
done := make(chan struct{})
go SayHello(done) // FIRST START goroutine
SayHello(nil) // And then call SayHello() in the main goroutine
<-done // Wait for completion
Tuesday, June 1, 2021
 
wavyGravy
answered 7 Months ago
74

If I have gotten it correctly, what you want is to prevent simultaneous execution of some part of each function and other functions. The following code does this: fmt.Println lines won't happen as other routines are running. Here's what happens: when execution gets to the print section, it waits until other routines end, if they are running, and while this print line is executing other routines don't start and wait. I hope that is what you are looking for. Correct me if I'm wrong about this.

package main

import (
    "fmt"
    "rand"
    "sync"
)

var (
    mutex1, mutex2, mutex3 sync.Mutex
    wg sync.WaitGroup
)

func Routine1() {
    mutex1.Lock()
    // do something
    for i := 0; i < 200; i++ {
        mutex2.Lock()
        mutex3.Lock()
        fmt.Println("value of z")
        mutex2.Unlock()
        mutex3.Unlock()
    }
    // do something
    mutex1.Unlock()
    wg.Done()
}

func Routine2() {
    mutex2.Lock()
    // do something
    for i := 0; i < 200; i++ {
        mutex1.Lock()
        mutex3.Lock()
        fmt.Println("value of z")
        mutex1.Unlock()
        mutex3.Unlock()
    }
    // do something
    mutex2.Unlock()
    wg.Done()
}

func Routine3() {
    mutex3.Lock()
    // do something
    for i := 0; i < 200; i++ {
        mutex1.Lock()
        mutex2.Lock()
        fmt.Println("value of z")
        mutex1.Unlock()
        mutex2.Unlock()
    }
    // do something
    mutex3.Unlock()
    wg.Done()
}

func main() {
    wg.Add(3)
    go Routine1()
    go Routine2()
    Routine3()
    wg.Wait()
}

UPDATE: Let me explain these three mutex here: a mutex is, as documentation says: "a mutual exclusion lock." That means when you call Lock on a mutex your code just waits there if somebody else have locked the same mutex. Right after you call Unlock that blocked code will be resumed.

Here I put each function in its own mutex by locking a mutex at the beginning of the function and unlocking it the end. By this simple mechanism you can avoid running any part of code you want at the same time as those functions. For instance, everywhere you want to have a code that should not be running when Routine1 is running, simply lock mutex1 at the beginning of that code and unlock at at the end. That is what I did in appropriate lines in Routine2 and Routine3. Hope that clarifies things.

Thursday, August 5, 2021
 
superhero
answered 4 Months ago
38

Try print the plot if you are calling it from another function or in Shiny:

myplot <- ggplot(data, aes(x = X, y = Y, group = group)) + geom_point() 

print(myplot)
Saturday, August 7, 2021
 
inieto
answered 4 Months ago
37

A quick bit of looking at the assembly output shows

$ go build -gcflags -S z.go

The getNumber() function does store its results to the stack

"".getNumber t=1 size=16 value=0 args=0x10 locals=0x0
    0x0000 00000 (z.go:5)   TEXT    "".getNumber+0(SB),4,$0-16
    0x0000 00000 (z.go:6)   MOVQ    "".i+8(FP),BX
    0x0005 00005 (z.go:6)   MOVQ    BX,"".~r1+16(FP)
    0x000a 00010 (z.go:6)   RET ,

So when it is called from a goroutine, it does store its results to the stack. However this is a new stack which is destroyed when the goroutine ends so there is no possibility of retrieving the return value.

"".main t=1 size=96 value=0 args=0x0 locals=0x18
    0x0000 00000 (z.go:9)   TEXT    "".main+0(SB),$24-0
    0x0000 00000 (z.go:9)   MOVQ    (TLS),CX
    0x0009 00009 (z.go:9)   CMPQ    SP,16(CX)
    0x000d 00013 (z.go:9)   JHI ,22
    0x000f 00015 (z.go:9)   CALL    ,runtime.morestack_noctxt(SB)
    0x0014 00020 (z.go:9)   JMP ,0
    0x0016 00022 (z.go:9)   SUBQ    $24,SP
    0x001a 00026 (z.go:10)  MOVQ    $0,AX
    0x001c 00028 (z.go:10)  CMPQ    AX,$10
    0x0020 00032 (z.go:10)  JGE $0,74
    0x0022 00034 (z.go:11)  MOVQ    AX,"".i+16(SP)
    0x0027 00039 (z.go:11)  MOVQ    AX,(SP)
    0x002b 00043 (z.go:11)  MOVQ    $"".getNumber·f+0(SB),CX
    0x0032 00050 (z.go:11)  PUSHQ   CX,
    0x0033 00051 (z.go:11)  PUSHQ   $16,
    0x0035 00053 (z.go:11)  PCDATA  $0,$0
    0x0035 00053 (z.go:11)  CALL    ,runtime.newproc(SB)
    0x003a 00058 (z.go:11)  POPQ    ,CX
    0x003b 00059 (z.go:11)  POPQ    ,CX
    0x003c 00060 (z.go:10)  MOVQ    "".i+16(SP),AX
    0x0041 00065 (z.go:10)  INCQ    ,AX
    0x0044 00068 (z.go:10)  NOP ,
    0x0044 00068 (z.go:10)  CMPQ    AX,$10
    0x0048 00072 (z.go:10)  JLT $0,34
    0x004a 00074 (z.go:13)  MOVQ    $5,(SP)
    0x0052 00082 (z.go:13)  PCDATA  $0,$0
    0x0052 00082 (z.go:13)  CALL    ,time.Sleep(SB)
    0x0057 00087 (z.go:14)  ADDQ    $24,SP
    0x005b 00091 (z.go:14)  RET ,

However there is no way of retrieving these results.

Monday, August 16, 2021
 
davidb
answered 4 Months ago
63

You have no guarantee to observe changes made to the value of a variable in another goroutine without synchronization. See The Go Memory Model for details.

So if you want to change ctx.Response.Status in another goroutine, for this change to be guaranteed to be visible in the caller goroutine use synchronization.

There are multiple synchronization primitives. You can use channels or the sync package.

Using channels:

ch := make(chan int)

go func() {
    err = l.Save(file) 
    if err != nil {
        ctx.Response.Status = 500
        ctx.Response.Body = err
    } else {
        ctx.Response.Status = 204
    }
    ch <- 0 // Signal that ctx is updated
    // goroutine may do other works (not related to changing ctx)
}()

<- ch // Wait for the goroutine to finish updating ctx

Using sync.WaitGroup:

var wg sync.WaitGroup
wg.Add(1)

go func() {
    err = l.Save(file) 
    if err != nil {
        ctx.Response.Status = 500
        ctx.Response.Body = err
    } else {
        ctx.Response.Status = 204
    }
    wg.Done() // Signal that ctx is updated
    // goroutine may do other works (not related to changing ctx)
}()

wg.Wait() // Wait for the goroutine to finish updating ctx

Using sync.Mutex:

m := sync.Mutex{}
m.Lock()

go func() {
    err = l.Save(file) 
    if err != nil {
        ctx.Response.Status = 500
        ctx.Response.Body = err
    } else {
        ctx.Response.Status = 204
    }
    m.Unlock() // Signal that ctx is updated
    // goroutine may do other works (not related to changing ctx)
}()

m.Lock() // Wait for the goroutine to finish updating ctx

Note:

It is good practice to signal the completion (ctx update in your case) using defer so that if the started goroutine would end in some unexpected way (e.g. runtime panic), the caller goroutine would not get blocked forever. Note that however in this case the completion signal will only be sent at the end of the anonymous function (that's when deferred functions are executed).

Saturday, October 23, 2021
 
JZ.
answered 1 Month ago
JZ.
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share