golang并发编程中Goroutine 协程的实现
Go 协程(Goroutine)是 Go 语言提供的一种轻量级线程,由 Go 运行时来管理。是与其他函数同时运行的函数,它们是并发执行代码的基础。
在函数调用前加上 go 关键字,这次调用就会在一个新的 goroutine 中并发执行。当被调用的函数返回时,这个 goroutine 也自动结束。
需要注意的是,如果这个函数有返回值,那幺这个返回值会被丢弃。
Go 协程(Goroutine)之间通过通道(channel)进行通信,简单的说就是多个协程之间通信的管道。通道可以防止多个协程访问共享内存时发生资源争抢的问题。
要启动一个新的 Goroutine,只需要在函数调用前加上 go 关键字。例如:
这行代码会启动一个新的 Goroutine 来执行 myFunction。
在 Go 中,同步和通信通常通过通道(channel)来实现。通道是 Go 语言提供的一种类型安全的通信机制。
可以使用 make 函数创建通道:
使用 - 操作符可以发送和接收数据:
// 发送数据到通道ch - 42// 从通道接收数据value := -ch
创建带缓冲的通道:
ch := make(chan int, 100)
这样通道可以在不阻塞发送 Goroutine 的情况下缓冲一定数量的数据。
以下是一个简单的 Goroutine 和通道的示例:
package mainimport ( "fmt" "time")func worker(ch chan int) { for i := 0; i 5; i++ { ch - i time.Sleep(time.Second) } close(ch)}func main() { ch := make(chan int) go worker(ch) for val := range ch { fmt.Println(val) }}
在这个例子中,worker 函数向通道 ch 发送数据,然后 main 函数从通道 ch 接收数据并打印。
需要注意的是,如果主程序退出,所有未完成的 Goroutines 也会立即终止。因此,通常需要确保主程序等待所有 Goroutines 完成。例如,可以使用 sync.WaitGroup 来实现这一点:
package mainimport ( "fmt" "sync")func worker(wg *sync.WaitGroup, id int) { defer wg.Done() fmt.Printf("Worker %d starting\n", id) // 模拟工作 time.Sleep(time.Second) fmt.Printf("Worker %d done\n", id)}func main() { var wg sync.WaitGroup for i := 1; i = 5; i++ { wg.Add(1) go worker( wg, i) } wg.Wait() fmt.Println("All workers done")}
这个示例使用 sync.WaitGroup 来等待所有的 Goroutines 完成。wg.Add(1) 用于增加计数,wg.Done() 在 Goroutine 完成时减少计数,wg.Wait() 则阻塞直到所有的 Goroutines 完成。
协程、线程和进程是并发和并行编程中的三种主要概念。它们有不同的特性和适用场景,以下是它们的主要区别:
定义:
进程是操作系统中资源分配的基本单位。每个进程都有自己的内存空间、文件描述符和其他资源。特点:
隔离性:进程之间是相互独立的,一个进程的崩溃不会影响其他进程。开销大:进程之间切换的开销较大,需要保存和恢复大量上下文信息。通信复杂:进程间通信(IPC,如管道、消息队列、共享内存等)相对复杂。适用场景:
适用于需要高度隔离和独立运行的任务。适用于不同编程语言和不同平台之间的并发处理。定义:
线程是进程中的一个执行单元,属于进程的一部分。同一进程中的线程共享该进程的内存和其他资源。特点:
轻量级:相比进程,线程的创建和切换开销较小。共享资源:同一进程内的线程可以直接访问共享的内存和资源,但也因此带来了同步问题。并发执行:多个线程可以在多核 CPU 上并发执行。适用场景:
适用于需要并行处理的任务,如多线程服务器、并行计算等。适用于需要频繁切换和低开销的场景。定义:
协程是一种用户态的轻量级线程,也称为微线程或纤程。协程由程序自身管理调度,而不是操作系统。特点:
更轻量级:协程的创建和切换开销更小,因为不涉及内核态的切换。协作式调度:协程通过显式的让出操作(如yield)来切换,控制权由程序员掌握。共享内存:同一线程内的协程可以共享内存,但需要注意同步问题。适用场景:
适用于 I/O 密集型任务,如高并发网络服务器。适用于需要大量并发但对并行性要求不高的场景,如爬虫、异步编程等。各自的选择主要取决于具体的应用场景和性能需求。协程在现代编程中越来越受欢迎,尤其是在需要高并发和高效 I/O 操作的场景中。
golang并发编程中Goroutine 协程的实现