Go Language Goroutines: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
No edit summary
Line 6: Line 6:
In Go, [[Concurrent_(Parallel)_Programming#Concurrent|concurrency]] is implemented with goroutines, which is another name for threads. The language offers support for concurrent programming at syntactic level, with keywords like <code>[[Go_Language#go_keyword|go]]</code>, <code>[[Go_Language#chan_keyword|chan]]</code> and <code>[[Go_Language#select_keyword|select]]</code>.
In Go, [[Concurrent_(Parallel)_Programming#Concurrent|concurrency]] is implemented with goroutines, which is another name for threads. The language offers support for concurrent programming at syntactic level, with keywords like <code>[[Go_Language#go_keyword|go]]</code>, <code>[[Go_Language#chan_keyword|chan]]</code> and <code>[[Go_Language#select_keyword|select]]</code>.


A goroutine is the Go implementation of a [[Concurrent_(Parallel)_Programming#Threads|thread]]. Many goroutines execute within a single O/S thread. From the O/S point of view, only one thread is scheduled. The goroutine schedule is done by the '''Go runtime scheduler'''. The Go runtime scheduler uses a logical processor. The goroutines scheduled on a logical processor are executing [[Concurrent_(Parallel)_Programming#Concurrency|concurrently]], not [[Concurrent_(Parallel)_Programming#Parallelism||in parallel]]. However, it is possible to have more than one logical processor, each logical processors can be mapped onto an O/S thread, which may be scheduled to work on different cores. In this case, things may become parallel.
A goroutine is the Go implementation of a [[Concurrent_(Parallel)_Programming#Threads|thread]]. Many goroutines execute within a single O/S thread. From the O/S point of view, only one thread is scheduled. The goroutine schedule is done by the [[#Go_Runtime_Scheduler|Go runtime scheduler]]. The Go runtime scheduler uses a logical processor. The goroutines scheduled on a logical processor are executing [[Concurrent_(Parallel)_Programming#Concurrency|concurrently]], not [[Concurrent_(Parallel)_Programming#Parallelism||in parallel]]. However, it is possible to have more than one logical processor, each logical processors can be mapped onto an O/S thread, which may be scheduled to work on different cores. In this case, things may become parallel.


A goroutine is always created automatically, to run the <code>main()</code> function.
A goroutine is always created automatically, to run the <code>main()</code> function.

Revision as of 00:14, 6 September 2023

Internal

Overview

In Go, concurrency is implemented with goroutines, which is another name for threads. The language offers support for concurrent programming at syntactic level, with keywords like go, chan and select.

A goroutine is the Go implementation of a thread. Many goroutines execute within a single O/S thread. From the O/S point of view, only one thread is scheduled. The goroutine schedule is done by the Go runtime scheduler. The Go runtime scheduler uses a logical processor. The goroutines scheduled on a logical processor are executing concurrently, not |in parallel. However, it is possible to have more than one logical processor, each logical processors can be mapped onto an O/S thread, which may be scheduled to work on different cores. In this case, things may become parallel.

A goroutine is always created automatically, to run the main() function.

Creation and Invocation

To explicitly create a goroutine and schedule it, use the go keyword, by providing a function invocation.

func somefunc(i int) {
  ...
}

...

go somefunc(10)

Any function invocation can be used to be sent to a goroutine:

go fmt.Printf("something")

Lambdas can also be used:

...
go func(s string) {
  ...
  fmt.Println(s)
  ...
}("test")

Note that this syntax only schedules a goroutine. It is not determined when it will be actually executed.

what happens with the result of the function?

If the invocation is done from main(), the scheduler always seems to continue to execute main(), it does not preempt main() to executes the new goroutine. Also, given the fact that when main() exists, all other goroutines are forcibly terminated, unless there's a mechanism that ensures they will be executed, they might not be executed at all. It is bad practice to use time.Sleep() to preempt and delay main(), because we're making assumptions about timing, and these assumptions can be wrong, and also we're assuming that the scheduler will schedule the other goroutine, when the main goroutine goes to sleep.

Exiting

A goroutine exits when the code is complete.

When the main goroutine is complete, all other goroutines are forced to exit. It is said that those goroutines exit early.

Pausing

time.Sleep()

Synchronization

Synchronization restricts the scheduler's options but it is some times necessary when things in different goroutines must happen in a certain order. Go provides synchronization mechanisms for goroutines in the sync package: WaitGroup, Mutex, Once. . Unbuffered channels also provide synchronization between threads.

WaitGroup

WaitGroup

Mutex

Mutex

Once

Once

Communication

Communication between threads is essential for concurrent programming. Data can be sent to goroutines by simply providing it as arguments to the functions that are invoked with the go keyword. This only works when the goroutine is started, though. Another way to send data to goroutines is via channels. Goroutines can use channels to receive and send data to other goroutines.

Channels

Go Channels

Deadlock

The Go runtime detects a deadlock where all goroutines are locked. It does not detect partial deadlocks, when only a subset of goroutines are deadlocked.

Also see:

Concurrent (Parallel) Programming | Deadlock

Go Runtime Scheduler

The Go runtime scheduler schedules goroutines.