golang并发编程中Goroutine 协程的实现

 更新时间:2024年10月22日 10:34:34   作者:怪我冷i  
Go语言中的协程是一种轻量级线程,通过在函数前加go关键字来并发执行,具有动态栈、快速启动和低内存使用等特点,本文就来详细的介绍一下,感兴趣的可以了解一下

Go 协程(Goroutine)是 Go 语言提供的一种轻量级线程,由 Go 运行时来管理。是与其他函数同时运行的函数,它们是并发执行代码的基础。

在函数调用前加上 go 关键字,这次调用就会在一个新的 goroutine 中并发执行。当被调用的函数返回时,这个 goroutine 也自动结束。

需要注意的是,如果这个函数有返回值,那么这个返回值会被丢弃。

Go 协程(Goroutine)之间通过通道(channel)进行通信,简单的说就是多个协程之间通信的管道。通道可以防止多个协程访问共享内存时发生资源争抢的问题。

启动 Goroutine

要启动一个新的 Goroutine,只需要在函数调用前加上 go 关键字。例如:

这行代码会启动一个新的 Goroutine 来执行 myFunction

Goroutine 的特性

  • 轻量级:Goroutine 比传统线程更轻量级。每个 Goroutine 使用的内存非常少,启动速度也更快。
  • 调度:Goroutine 由 Go 运行时管理和调度,而不是操作系统。
  • 栈管理:Goroutine 的栈是动态增长的,初始大小一般较小(如 2KB),但可以根据需要动态扩展,最大可达 1GB。

同步和通信

在 Go 中,同步和通信通常通过通道(channel)来实现。通道是 Go 语言提供的一种类型安全的通信机制。

创建通道

可以使用 make 函数创建通道:

发送和接收

使用 <- 操作符可以发送和接收数据:

// 发送数据到通道
ch <- 42
// 从通道接收数据
value := <-ch

带缓冲的通道

创建带缓冲的通道:

ch := make(chan int, 100)

这样通道可以在不阻塞发送 Goroutine 的情况下缓冲一定数量的数据。

示例代码

以下是一个简单的 Goroutine 和通道的示例:

package main
import (
 "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 也会立即终止。因此,通常需要确保主程序等待所有 Goroutines 完成。例如,可以使用 sync.WaitGroup 来实现这一点:

package main

import (
 "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 完成。

协程、线程、进程

协程、线程和进程是并发和并行编程中的三种主要概念。它们有不同的特性和适用场景,以下是它们的主要区别:

进程 (Process)

定义

  • 进程是操作系统中资源分配的基本单位。
  • 每个进程都有自己的内存空间、文件描述符和其他资源。

特点

  • 隔离性:进程之间是相互独立的,一个进程的崩溃不会影响其他进程。
  • 开销大:进程之间切换的开销较大,需要保存和恢复大量上下文信息。
  • 通信复杂:进程间通信(IPC,如管道、消息队列、共享内存等)相对复杂。

适用场景

  • 适用于需要高度隔离和独立运行的任务。
  • 适用于不同编程语言和不同平台之间的并发处理。

线程 (Thread)

定义

  • 线程是进程中的一个执行单元,属于进程的一部分。
  • 同一进程中的线程共享该进程的内存和其他资源。

特点

  • 轻量级:相比进程,线程的创建和切换开销较小。
  • 共享资源:同一进程内的线程可以直接访问共享的内存和资源,但也因此带来了同步问题。
  • 并发执行:多个线程可以在多核 CPU 上并发执行。

适用场景

  • 适用于需要并行处理的任务,如多线程服务器、并行计算等。
  • 适用于需要频繁切换和低开销的场景。

协程 (Coroutine)

定义

  • 协程是一种用户态的轻量级线程,也称为微线程或纤程。
  • 协程由程序自身管理调度,而不是操作系统。

特点

  • 更轻量级:协程的创建和切换开销更小,因为不涉及内核态的切换。
  • 协作式调度:协程通过显式的让出操作(如 yield)来切换,控制权由程序员掌握。
  • 共享内存:同一线程内的协程可以共享内存,但需要注意同步问题。

适用场景

  • 适用于 I/O 密集型任务,如高并发网络服务器。
  • 适用于需要大量并发但对并行性要求不高的场景,如爬虫、异步编程等。

总结

  • 进程:资源隔离好,开销大,适用于独立运行的任务。
  • 线程:资源共享,开销较小,适用于需要并行处理的任务。
  • 协程:更轻量级,用户态调度,适用于大量并发的 I/O 密集型任务。

各自的选择主要取决于具体的应用场景和性能需求。协程在现代编程中越来越受欢迎,尤其是在需要高并发和高效 I/O 操作的场景中。

到此这篇关于golang并发编程中Goroutine 协程的实现的文章就介绍到这了,更多相关golang Goroutine 协程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go语言WaitGroup使用时需要注意的坑

    Go语言WaitGroup使用时需要注意的坑

    Go语言中WaitGroup的用途是它能够一直等到所有的goroutine执行完成,并且阻塞主线程的执行,直到所有的goroutine执行完成。之前一直使用也没有问题,但最近通过同事的一段代码引起了关于WaitGroup的注意,下面这篇文章就介绍了WaitGroup使用时需要注意的坑及填坑。
    2016-12-12
  • Golang如何编写内存高效及CPU调优的Go结构体

    Golang如何编写内存高效及CPU调优的Go结构体

    这篇文章主要介绍了Golang如何编写内存高效及CPU调优的Go结构体,结构体是包含多个字段的集合类型,用于将数据组合为记录
    2022-07-07
  • Golang实现请求限流的几种办法(小结)

    Golang实现请求限流的几种办法(小结)

    这篇文章主要介绍了Golang实现请求限流的几种办法(小结),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10
  • Golang 流水线设计模式实践示例详解

    Golang 流水线设计模式实践示例详解

    这篇文章主要为大家介绍了Golang 流水线设计模式实践示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • 使用Go实现伪静态URL重写功能

    使用Go实现伪静态URL重写功能

    在Web开发中,伪静态URL已成为优化网站架构和提升SEO的常用技术手段,伪静态URL是一种介于动态URL和静态URL之间的解决方案,本文给大家介绍了如何使用Go实现伪静态URL重写功能,需要的朋友可以参考下
    2024-08-08
  • Go语言使用Gob传输数据

    Go语言使用Gob传输数据

    本文主要介绍了Go语言使用Gob传输数据,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • Go Gin 处理跨域问题解决

    Go Gin 处理跨域问题解决

    在前后端分离的项目中,经常会遇到跨域问题,本文主要介绍了Go Gin 处理跨域问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-05-05
  • go语言题解LeetCode228汇总区间示例详解

    go语言题解LeetCode228汇总区间示例详解

    这篇文章主要为大家介绍了go语言题解LeetCode228汇总区间示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • 使用gopacket解析协议层中的相关数据方式

    使用gopacket解析协议层中的相关数据方式

    文章介绍使用Wireshark抓取ping数据包并保存为pcap格式,通过Go语言gopacket解析,提取IP版本号、指定标识的数据包长度及应用层ICMP字符串内容,展示TCP/IP协议族解析的简便方法
    2025-07-07
  • Go语言使用context控制协程取消的方法步骤

    Go语言使用context控制协程取消的方法步骤

    本文将通过一个实际案例,使用 context 控制协程的取消,避免资源泄露,实现优雅退出,具有一定的参考价值,感兴趣的可以了解一下
    2025-08-08

最新评论