Explore tens of thousands of sets crafted by our community.
Go Concurrency
27
Flashcards
0/27
What is a WaitGroup in Go?
A WaitGroup is used to wait for a collection of Goroutines to finish executing. The main Goroutine calls Add to set the number of Goroutines to wait for. Then each of the Goroutines runs and calls Done when finished. At the same time, Wait can be used to block until all Goroutines have finished. ```go var wg sync.WaitGroup for i := 0; i < 3; i++ { wg.Add(1) go func(i int) { defer wg.Done() // Perform work }(i) } wg.Wait() // Wait for all Goroutines to finish ```
How do you stop a Goroutine?
There is no direct way to stop a Goroutine; it should exit on its own when it completes its work. However, you can implement a cancellation pattern using channels to signal a Goroutine to stop. ```go done := make(chan bool) go func() { for { select { case <-done: return default: // Do work } } }() ```
What is a deadlock in concurrency?
A deadlock is a situation where two or more Goroutines are waiting for each other to release resources, or they are holding on to resources that the other needs, effectively stopping all execution. ```go func main() { lock1, lock2 := &sync.Mutex{}, &sync.Mutex{} go func() { lock1.Lock() lock2.Lock() lock1.Unlock() lock2.Unlock() }() go func() { lock2.Lock() lock1.Lock() lock2.Unlock() lock1.Unlock() }() // deadlocked Goroutines } ```
How do you synchronize Goroutines?
Goroutines can be synchronized using WaitGroups, Mutexes, or Channels. A WaitGroup waits for a collection of Goroutines to finish. A Mutex provides a locking mechanism to ensure that only one Goroutine is running the critical section of code at a time. ```go var wg sync.WaitGroup wg.Add(1) go myFunc() wg.Wait() ```
How do you implement a producer-consumer pattern in Go?
The producer-consumer pattern can be implemented using channels. The producer sends data to a channel from which the consumer reads. ```go ch := make(chan int) // Producer go func() { for i := 0; i < 10; i++ { ch <- i } close(ch) }() // Consumer for v := range ch { fmt.Println(v) } ```
When should you use a sync.Mutex over channels in Go?
A sync.Mutex is more suitable for simple shared data protection where you don't require channel's communication semantics. It's also typically more performant in these scenarios. ```go var mu sync.Mutex var sharedResource int mu.Lock() sharedResource = 42 mu.Unlock() ```
What are buffered channels used for?
Buffered channels in Go are used when you want to limit the number of Goroutines running at any one time or allow a certain number of messages to queue up before the receiver is ready to deal with them. This can help to control the flow of data and reduce memory consumption by cherunnelling.
How do you pass a channel as a parameter to a function?
To pass a channel to a function, you specify the channel type as a parameter in the function signature, and then pass the channel as an argument when you call the function. ```go func sendMessage(ch chan string, msg string) { ch <- msg } func main() { messageChannel := make(chan string) go sendMessage(messageChannel, "Hello, channels!") } ```
What are buffered channels used for?
Buffered channels in Go are used when you want to limit the number of Goroutines running at any one time or allow a certain number of messages to queue up before the receiver is ready to deal with them. This can help to control the flow of data and reduce memory consumption by cherunnelling or work processes that may need to occur at a controlled rate or with a certain amount of concurrency. ```go ch := make(chan int, 100) // Buffer allows 100 items to queue up ```
What is a Goroutine in Go?
A Goroutine is a lightweight thread managed by the Go runtime. Goroutines run in the same address space, so access to shared memory must be synchronized. To start a Goroutine, use the 'go' keyword followed by the function call. ```go go functionName(parameters) ```
How to range over a channel in Go?
To range over a channel, use a for loop combined with the range keyword. This loops until the channel is closed. ```go ch := make(chan int) go func() { for i := 0; i < 5; i++ { ch <- i } close(ch) }() for n := range ch { fmt.Println(n) } ```
What is a Channel in Go?
A Channel is a data structure used to communicate between Goroutines. A channel can be thought of as a pipe through which Goroutines can send and receive values. Channels are typed by the values they convey. ```go ch := make(chan int) ```
What is the purpose of the 'sync/atomic' package in Go?
The 'sync/atomic' package provides low-level atomic memory primitives that enable the implementation of synchronization algorithms. They are used to perform atomic operations on simple types such as incrementing a counter without the need for mutex locking. ```go var count int32 atomic.AddInt32(&count, 1) // Atomically increments 'count' by 1 ```
How can you ensure a deferred function is executed within a Goroutine?
To ensure deferred functions are executed, they must be placed within the Goroutine that you want them to be executed in. Deferred calls are executed when the surrounding function returns. ```go go func() { defer fmt.Println("Deferred call in Goroutine") // Perform work }() ```
What is a race condition in concurrency?
A race condition occurs when multiple threads or Goroutines access shared data and try to change it at the same time. This can lead to inconsistent results or corrupt data. ```go import "sync" var counter int var wg sync.WaitGroup var mutex sync.Mutex for i := 0; i < 10; i++ { wg.Add(1) go func() { mutex.Lock() temp := counter temp++ counter = temp mutex.Unlock() wg.Done() }() } wg.Wait() ```
How do you create a buffered channel in Go?
A buffered channel is created by specifying the capacity in the make function call. This defines the number of values the channel can hold without a receiver. ```go ch := make(chan int, 10) // Channel with buffer of size 10 ```
How do you dynamically create Goroutines in a loop?
To dynamically create Goroutines within a loop, ensure you pass the loop variables as function arguments to prevent closure over the loop variable. ```go for i := 0; i < n; i++ { go func(i int) { // use i within the Goroutine }(i) } ```
How would you explain channel direction in function parameters?
Channel direction in function parameters specifies whether the channel is used only to send or only to receive values. Specifying the direction can increase type-safety and clarify the function's intent. Example: 'chan<- int' is a send-only channel and '<-chan int' is a receive-only channel. ```go func sendOnly(ch chan<- int, value int) { ch <- value } func receiveOnly(ch <-chan int) int { return <-ch } ```
Explain Goroutine leaks in Go.
Goroutine leaks occur when a Goroutine is blocked forever, never being able to proceed with execution or to exit. This often happens when the Goroutine is waiting on an event that never occurs. ```go leakyFunc := func(ch chan int) { for { select { case val := <-ch: // process val default: // if ch is never closed, Goroutine leaks } } } ```
What is the purpose of a Mutex in Go?
A Mutex (mutual exclusion lock) is used to ensure that only one Goroutine at a time can access a particular section of code or data, preventing race conditions when multiple Goroutines access shared resources. ```go var mutex sync.Mutex mutex.Lock() // critical section golloballySharedResource = update(golloballySharedResource) mutex.Unlock() ```
Does Go have thread-local storage (TLS)?
Go does not have traditional thread-local storage as seen in other languages. Instead, goroutines can use local variables and closures, or the 'context' package can be used to pass request-scoped values through a chain of function calls. ```go func myFunc(ctx context.Context) { // Access context-scoped value val := ctx.Value("myKey") } ```
What kind of tasks are suitable for Goroutines?
Tasks suitable for Goroutines are generally those that are independent, can be executed concurrently or in parallel, are I/O-bound, or require waiting, such as waiting for a response from an external service.
What is a select statement in Go?
A select statement is similar to a switch but for channels. It blocks until one of its cases is ready to execute. It's often used to handle multiple channel operations in a non-blocking way. ```go select { case msg := <-channel1: // handle msg case channel2 <- msg: // sent msg on channel2 default: // executed if no other case is ready } ```
How do you make a Goroutine sleep for a specific amount of time?
Use the `time.Sleep` function to make a Goroutine sleep. This pauses the current Goroutine for the duration specified. ```go time.Sleep(2 * time.Second) // Sleeps for 2 seconds ```
What are the best practices for using Goroutines?
Best practices include starting Goroutines when necessary, avoiding starting an excessive number of Goroutines, and ensuring that they complete their work, either by returning or by properly managing their lifecycle with synchronization mechanisms.
When to use 'close' on a channel?
A channel should be closed to indicate that no more values will be sent on it. This is important to prevent Goroutines from blocking forever waiting for values. Closing is also necessary to use the range loop to receive values from the channel. ```go go func() { for i := 0; i < 10; i++ { ch <- i } close(ch) }() for n := range ch { fmt.Println(n) } ```
What is the zero value of a channel in Go?
The zero value of a channel is nil. A nil channel is not ready for communication and will block indefinitely if you try to send or receive from it. ```go var ch chan int // ch is nil, and will block if used before it's initialized ```
© Hypatia.Tech. 2024 All rights reserved.