Heim >Backend-Entwicklung >Golang >Parallelität in Go: Von den Grundlagen zu fortgeschrittenen Konzepten

Parallelität in Go: Von den Grundlagen zu fortgeschrittenen Konzepten

Linda Hamilton
Linda HamiltonOriginal
2024-10-03 06:11:30436Durchsuche

Concurrency in Go: From Basics to Advanced Concepts

Table of Contents

  1. Introduction to Concurrency
  2. Concurrency vs Parallelism
  3. Go-routines: The Building Blocks of Concurrency
  4. Channels: Communication Between Go-routines
  5. Select Statement: Managing Multiple Channels
  6. Synchronization Primitives
  7. Concurrency Patterns
  8. Context Package: Managing Cancellation and Timeouts.
  9. Best Practices and Common Pitfalls**

1.Introduction to Concurrency

Concurrency is the ability to handle multiple tasks simultaneously. In Go, concurrency is a first-class citizen, built into the language's core design. Go's approach to concurrency is based on Communicating Sequential Processes (CSP), a model that emphasizes communication between processes rather than shared memory.

2.Concurrency vs Parallelism:

Go-routines enable concurrency, which is the composition of independently executing processes.
Parallelism (simultaneous execution) may occur if the system has multiple CPU cores and the Go runtime schedules go-routines to run in parallel.

3. Go-routines:
The Building Blocks of Concurrency is Go-routines are lightweight threads managed by the Go runtime. It's a function or method that runs concurrently with other functions or methods. Go-routines are the foundation of Go's concurrency model.

Key Characteristics:

  • Lightweight: Go-routines are much lighter than OS threads. You can easily create thousands of go-routines without significant performance impact.
  • Managed by Go runtime: The Go scheduler handles the distribution of go-routines across available OS threads.
  • Cheap creation: Starting a go-routine is as simple as using the go keyword before a function call.
  • Stack size: Go-routines start with a small stack (around 2KB) that can grow and shrink as needed.

Creating a Go-routine:
To start a go-routine, you simply use the go keyword followed by a function call:

go functionName()

Or with an anonymous function:

go func() {
    // function body
}()

Go-routine Scheduling:

  • The Go runtime uses a M:N scheduler, where M go-routines are scheduled onto N OS threads.
  • This scheduler is non-preemptive, meaning go-routines yield control when they are idle or logically blocked.

Communication and Synchronization:

  • Goroutines typically communicate using channels, adhering to the "Don't communicate by sharing memory; share memory by communicating" principle.
  • For simple synchronization, you can use primitives like sync.WaitGroup or sync.Mutex.

Example with Explanation:

package main

import (
    "fmt"
    "time"
)

func printNumbers() {
    for i := 1; i <= 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Printf("%d ", i)
    }
}

func printLetters() {
    for i := 'a'; i <= 'e'; i++ {
        time.Sleep(150 * time.Millisecond)
        fmt.Printf("%c ", i)
    }
}

func main() {
    go printNumbers()
    go printLetters()
    time.Sleep(2 * time.Second)
    fmt.Println("\nMain function finished")
}

Explanation:

  • We define two functions: printNumbers and printLetters.
  • In main, we start these functions as goroutines using the go keyword.
  • The main function then sleeps for 2 seconds to allow the goroutines to complete.
  • Without goroutines, these functions would run sequentially. With goroutines, they run concurrently.
  • The output will show numbers and letters interleaved, demonstrating concurrent execution.

Goroutine Lifecycle:

  • A goroutine starts when created with the go keyword.
  • It terminates when its function completes or when the program exits.
  • Goroutines can be leaked if not properly managed, so it's important to ensure they can exit.

Best Practices:

  • Don't create goroutines in libraries; let the caller control concurrency.
  • Be cautious about creating an unbounded number of goroutines.
  • Use channels or sync primitives to coordinate between goroutines.
  • Consider using worker pools for managing multiple goroutines efficiently.

Simple example with explanations of go-routines

package main

import (
    "fmt"
    "time"
)

// printNumbers is a function that prints numbers from 1 to 5
// It will be run as a goroutine
func printNumbers() {
    for i := 1; i <= 5; i++ {
        time.Sleep(500 * time.Millisecond) // Sleep for 500ms to simulate work
        fmt.Printf("%d ", i)
    }
}

// printLetters is a function that prints letters from 'a' to 'e'
// It will also be run as a goroutine
func printLetters() {
    for i := 'a'; i <= 'e'; i++ {
        time.Sleep(300 * time.Millisecond) // Sleep for 300ms to simulate work
        fmt.Printf("%c ", i)
    }
}

func main() {
    // Start printNumbers as a goroutine
    // The 'go' keyword before the function call creates a new goroutine
    go printNumbers()

    // Start printLetters as another goroutine
    go printLetters()

    // Sleep for 3 seconds to allow goroutines to finish
    // This is a simple way to wait, but not ideal for production code
    time.Sleep(3 * time.Second)

    // Print a newline for better formatting
    fmt.Println("\nMain function finished")
}

4.Channels :

Channels are a core feature in Go that allow go-routines to communicate with each other and synchronize their execution. They provide a way for one go-routine to send data to another go-routine.

Purpose of Channels

Channels in Go serve two main purposes:
a) Communication: They allow goroutines to send and receive values to and from each other.
b) Synchronization: They can be used to synchronize execution across goroutines.

Creation: Channels are created using the make function:

ch := make(chan int)  // Unbuffered channel of integers

Sending: Values are sent to a channel using the <- operator:

ch <- 42  // Send the value 42 to the channel

Receiving: Values are received from a channel using the <- operator:

value := <-ch  // Receive a value from the channel

Types of Channels

a) Unbuffered Channels:

  • Created without a capacity: ch := make(chan int)
  • Sending blocks until another goroutine receives.
  • Receiving blocks until another goroutine sends.
ch := make(chan int)
go func() {
    ch <- 42  // This will block until the value is received
}()
value := <-ch  // This will receive the value

b) Buffered Channels:

  • Created with a capacity: ch := make(chan int, 3)
  • Sending only blocks when the buffer is full.
  • Receiving only blocks when the buffer is empty.
ch := make(chan int, 2)
ch <- 1  // Doesn't block
ch <- 2  // Doesn't block
ch <- 3  // This will block until a value is received

Channel Directions

Channels can be directional or bidirectional:

  • Bidirectional: chan T
  • Send-only: chan<- T
  • Receive-only: <-chan T

Example :

func send(ch chan<- int) {
    ch <- 42
}

func receive(ch <-chan int) {
    value := <-ch
    fmt.Println(value)
}

Closing Channels

Channels can be closed to signal that no more values will be sent:

close(ch)

Receiving from a closed channel:

If the channel is empty, it returns the zero value of the channel's type.
You can check if a channel is closed using a two-value receive:

value, ok := <-ch
if !ok {
    fmt.Println("Channel is closed")
}

Ranging over Channels

You can use a for range loop to receive values from a channel until it's closed:

for value := range ch {
    fmt.Println(value)
}

Hey, Thank you for staying until the end! I appreciate you being valuable reader and learner. Please follow me here and also on my Linkedin and GitHub .

Das obige ist der detaillierte Inhalt vonParallelität in Go: Von den Grundlagen zu fortgeschrittenen Konzepten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn