Skip to content

Commit

Permalink
feat: goroutine doc
Browse files Browse the repository at this point in the history
  • Loading branch information
suyuan32 committed Apr 28, 2024
1 parent 788f358 commit b1d798c
Show file tree
Hide file tree
Showing 3 changed files with 264 additions and 1 deletion.
131 changes: 131 additions & 0 deletions src/en/guide/concepts/golang/9-goroutine.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
---
order: 9
title: Goroutine
icon: line-md:star-filled
head:
- - meta
- name: keywords
content: golang, goroutine, 协程, 并发编程, 并发模型
---


## Goroutine | Coroutine

Goroutine is the concurrency model in the Go programming language. It is a lightweight thread managed by the Go runtime, and we can also refer to it as a coroutine.

::: tip Advantages
- **Lightweight**: The initial stack size of a Goroutine is only 2KB, but it can dynamically grow up to 1GB.
- **Fast Startup**: Goroutines start quickly, typically within 1 to 2 microseconds.
- **Efficient Scheduling**: The Goroutine scheduler uses an M:N model, mapping M Goroutines to N OS threads for efficient scheduling.
- **Simple Communication**: Goroutines communicate with each other using channels, enabling data sharing.
- **Lock-Free**: Goroutines communicate via channels without the need for locks.
- **High Concurrency**: You can easily create hundreds of thousands of Goroutines, achieving high concurrency.
- **High Performance**: The Goroutine scheduler uses preemptive scheduling, resulting in high performance.
:::

::: warning
Goroutine is a crucial feature in Go and forms the core of Go's concurrency programming. Understanding how to use and reason about Goroutines is essential for learning Go. For writing high-performance concurrent programs, Goroutines are an excellent choice.
:::

### Creating Goroutines

Creating asynchronous Goroutines in Go is straightforward due to its emphasis on this fundamental feature. You only need to prefix a function call with the `go` keyword, which is simpler than in most other programming languages.

```go
package main

import (
"fmt"
"time"
)

func main() {
go func() {
for {
fmt.Println("running...")
time.Sleep(time.Second)
}
}()

time.Sleep(5 * time.Second)
}
```

By using `go` before any function call, you create a Goroutine that runs in the background without blocking the main thread.

::: tip Stopping Goroutines
- **Natural Termination**: Goroutines automatically end when the function execution completes.
- **Timeout Termination**: You can set a timeout for a Goroutine using `context.WithTimeout()` or `context.WithDeadline()`.
- **Manual Termination**: Manually terminate a Goroutine using `context.WithCancel()`.
- **Channel Termination**: Use channels for communication between Goroutines to signal termination.
:::

### Goroutines and Channels

In Go, communication between Goroutines often involves sharing data. Channels provide a way for Goroutines to communicate with each other.

```go
package main

import (
"fmt"
"time"
)

func main() {
ch := make(chan int)

go func() {
for {
select {
case <-ch:
fmt.Println("exit")
return
default:
fmt.Println("running...")
time.Sleep(time.Second)
}
}
}()

time.Sleep(5 * time.Second)
ch <- 1
}
```

In the example above, we create a channel `ch`. The main thread sends data to `ch`, and the Goroutine listens to `ch` using a `select` statement. When data arrives in `ch`, the Goroutine exits.

Here's another example of communication between Goroutines using channels:

```go
package main

import (
"fmt"
"time"
)

func main() {
ch := make(chan string)

go sendData(ch)
go getData(ch)

time.Sleep(1e9)
}

func sendData(ch chan string) {
ch <- "BiliBili"
ch <- "Youtube"
}

func getData(ch chan string) {
var input string
for {
input = <-ch
fmt.Printf("%s ", input)
}
}

// Output: BiliBili Youtube
```
132 changes: 132 additions & 0 deletions src/guide/concepts/golang/9-goroutine.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
---
order: 9
title: Goroutine
icon: line-md:star-filled
head:
- - meta
- name: keywords
content: golang, goroutine, 协程, 并发编程, 并发模型
---

## Goroutine | 协程

Goroutine 是 Go 语言的并发编程模型,它是一种轻量级的线程,由 Go 运行时管理,我们也可以称之为协程。

::: tip 优点
- **轻量级**:Goroutine 的栈空间初始大小只有 2KB,可以动态扩容,最大可达 1GB
- **快速启动**:Goroutine 的启动时间只有 1~2us
- **高效调度**:Goroutine 的调度器采用 M:N 模型,可以将 M 个 Goroutine 映射到 N 个 OS 线程上,实现高效调度
- **通信简单**:Goroutine 之间通过 Channel 进行通信,实现数据共享
- **无锁**:Goroutine 之间通过 Channel 进行通信,无需加锁
- **高并发**:Goroutine 可以轻松创建数十万个,实现高并发
- **高性能**:Goroutine 的调度器采用抢占式调度,实现高性能
:::

::: warning
Goroutine 是 Golang 十分重要的特性,也是 Golang 的并发编程的核心,掌握 Goroutine 的使用和原理对于 Golang 的学习至关重要。对于编写高性能的并发程序,Goroutine 是一个非常好的选择。
:::

### 创建 Goroutine

由于 Goroutine 是 Golang 非常重视的基本功能,因此在 Golang 中创建异步 Goroutine 非常简单,只需要在函数调用前加上 `go` 关键字即可,比绝大部分的编程语言都要简单。

```go
package main

import (
"fmt"
"time"
)

func main() {
go func() {
for {
fmt.Println("running...")
time.Sleep(time.Second)
}
}()

time.Sleep(5 * time.Second)
}
```

使用 `go` 加上任意 `func` 即可创建一个 Goroutine,Goroutine 会在后台执行,不会阻塞主线程。

::: tip 如何停止 Goroutine
- **运行结束**:Goroutine 会在函数运行结束后自动结束
- **超时结束**:通过 `context.WithTimeout()``context.WithDeadline()` 可以设置 Goroutine 的超时时间
- **手动结束**:通过 `context.WithCancel()` 可以手动结束 Goroutine
- **通道结束**:通过 Channel 通信,可以结束 Goroutine
:::

### Goroutine 和 Channel

我们知道,无论是在线程还是协程,在运行的时候都会遇到贡献数据或传递数据的情况,在 Golang 中,我们可以通过 Channel 来实现 Goroutine 之间的通信。

```go
package main

import (
"fmt"
"time"
)

func main() {
ch := make(chan int)

go func() {
for {
select {
case <-ch:
fmt.Println("exit")
return
default:
fmt.Println("running...")
time.Sleep(time.Second)
}
}
}()

time.Sleep(5 * time.Second)
ch <- 1
}
```

在上面的例子中,我们创建了一个 Channel `ch`,在主线程中向 `ch` 中发送了一个数据,Goroutine 中通过 `select` 语句监听 `ch`,当 `ch` 中有数据时,Goroutine 会退出。

协程之间通过 Channel 通信的例子:

```go
package main

import (
"fmt"
"time"
)

func main() {
ch := make(chan string)

go sendData(ch)
go getData(ch)

time.Sleep(1e9)
}

func sendData(ch chan string) {
ch <- "BiliBili"
ch <- "Youtube"
}

func getData(ch chan string) {
var input string
for {
input = <-ch
fmt.Printf("%s ", input)
}
}

// 结果: BiliBili Youtube
```


2 changes: 1 addition & 1 deletion src/guide/standard/1-golang.md
Original file line number Diff line number Diff line change
Expand Up @@ -1542,5 +1542,5 @@ close(stop) // 指示 goroutine 停止

### 指定 map, slice 的容量

如果提前知道大概容量吗,请提前赋值,以避免不必要的内存分配和自动扩容。
如果提前知道大概容量,请提前赋值,以避免不必要的内存分配和自动扩容。

0 comments on commit b1d798c

Please sign in to comment.