当前位置: 首页 > article >正文

Go语言协程Goroutine高级用法(一)

什么协程

在Go语言中,协程就是一种轻量的线程,是并发编程的单元,由Go来管理,所以在GO层面的协程会更加的轻量、高效、开销更小,并且更容易实现并发编程。

轻量级线程

  1. Go语言中协程(线程)与传统系统层面的线程相比,实在是太轻量了,能小到2kb
  2. 由于协程的轻量特性,可以更高效地利用系统资源。相较于传统的线程,协程的创建和销毁的开销更小,使得程序更具有扩展性和性能优势。

Go自身管理

  1. 在 Go 中,这些工作由运行时系统自动完成。这样我们就可以更专注于业务逻辑,而不必过多关心底层线程管理的细节。

并发的基本单元

  1. 协程是并发编程的基本单元,可以同时执行多个协程,而它们之间的调度和切换由运行时系统负责。
  2. 在程序中更容易实现高效的并发,处理多个任务而无需显式地创建和管理线程。
  3. 使用协程,我们可以轻松地实现并发任务,例如同时处理多个网络请求、执行后台任务等。由于协程的轻量特性,可以创建数千甚至数百万个协程而不会造成系统负担。

使用通道通信

  1. 协程之间可以通过通道进行通信,这是一种在协程之间安全地传递数据和同步操作的机制。通道是一种强大的工具,用于协程之间的协作和数据传递。

协程的基本操作

创建协程

- 语法: `go 函数(函数列表)`
package main  
  
import (  
    "fmt"  
    "time")  
  
func Hello() {  
    fmt.Println("hello world")  
}  
  
func main() {  
    go Hello()  
    fmt.Println("hello main")  
    time.Sleep(10 * time.Second)  
}

	

协程与主线程是并发执行的。

协程间通行

  • 主要通过channel来实现的
package main  
  
import (  
    "fmt"  
)  
  
func sendMessage(ch chan string, msg string) {  
    ch <- msg  
}  
  
func main() {  
    messagechan := make(chan string)  
    go sendMessage(messagechan, "Hello World")  
    msg := <-messagechan  
    fmt.Println(msg)  
}

协程间的同步

  • 使用sync包来实现的
  • waitgroup 是用来计数信号量的
package main  
  
import (  
    "fmt"  
    "sync")  
  
func worker(id int, wg *sync.WaitGroup) {  
    defer wg.Done()  
    fmt.Printf("worker %d starting\n", id)  
    fmt.Printf("worker %d done\n", id)  
}  
  
func main() {  
    var wg sync.WaitGroup  
    for i := 1; i <= 10; i++ {  
       wg.Add(1)  
       go worker(i, &wg)  
    }  
    wg.Wait()  
    fmt.Printf("all workers done\n")  
}

waitgroup确保主线程等待所有协程完成

协程的错误处理

  • 使用select语句和通道可以实现协程的错误处理
package main  
  
import (  
    "fmt"  
    "time")  
  
func dosomething(ch chan string) {  
    time.Sleep(2 * time.Second)  
    ch <- "hello world"  
}  
  
func main() {  
    ch := make(chan string)  
    go dosomething(ch)  
    select {  
    case msg := <-ch:  
       fmt.Println(msg)  
    case <-time.After(1 * time.Second):  
       fmt.Println("timeout")  
    }  
}

select 语句允许在多个通道操作中选择一个可用的操作,可以用来处理协程的超时等情况。

协程的高级操作

协程池

  • 协程池是一组预先创建的协程,用于执行并发任务,可以避免频繁创建和销毁协程的开销。
  • 使用缓冲通道来实现协程池
package main  
  
import (  
    "fmt"  
    "sync")  
  
func worker(id int, jobs <-chan int, results chan<- int) {  
    for j := range jobs {  
       fmt.Println("worker", id, "started job", j)  
       results <- j * 2  
    }  
}  
  
func main() {  
    const numJobs = 5  
    const numWorkers = 3  
  
    jobs := make(chan int, numJobs)  
    results := make(chan int, numJobs)  
  
    var wg sync.WaitGroup  
    for i := 1; i <= numWorkers; i++ {  
       wg.Add(1)  
       go func(i int) {  
          defer wg.Done()  
          worker(i, jobs, results)  
       }(i)  
    }  
    for j := 1; j <= 5; j++ {  
       jobs <- j  
    }  
    close(jobs)  
    go func() {  
       wg.Wait()  
       close(results)  
    }()  
    for result := range results {  
       fmt.Println("result", result)  
    }  
}

三个协程形成了协程池,从任务通道 jobs 中获取任务,处理后将结果发送到结果通道 results

超时控制

package main  
  
import (  
    "fmt"  
    "time")  
  
func dosomething(ch chan string) {  
    time.Sleep(2 * time.Second)  
    ch <- "hello world"  
}  
  
func main() {  
    ch := make(chan string)  
    go dosomething(ch)  
    select {  
    case msg := <-ch:  
       fmt.Println(msg)  
    case <-time.After(1 * time.Second):  
       fmt.Println("timeout")  
    }  
}

time.After 创建一个计时器,如果在指定时间内没有从通道 ch 中接收到结果,就会触发超时。

协程的取消

  • 使用 context 包提供的上下文(Context)来实现协程的取消。
package main  
  
import (  
    "context"  
    "fmt"    "time")  
  
func doSomething(ctx context.Context, ch chan string) {  
    select {  
    case <-ctx.Done():  
       ch <- "task completed successfully"  
    case <-time.After(1 * time.Second):  
       ch <- "task timed out"  
    }  
}  
  
func main() {  
    ctx, cancel := context.WithCancel(context.Background())  
    defer cancel()  
    ch := make(chan string)  
    go doSomething(ctx, ch)  
    time.Sleep(2 * time.Second)  
    cancel()  
    result := <-ch  
    fmt.Println(result)  
}

通过调用 cancel 函数取消协程的执行。


http://www.kler.cn/a/546357.html

相关文章:

  • React源码解读
  • Linux中安装open-webui报sqlite版本低的解决办法
  • MySQL无法连接到本地localhost的解决办法2024.11.8
  • 《刚刚问世》系列初窥篇-Java+Playwright自动化测试-23- 操作鼠标拖拽 - 番外篇(详细教程)
  • 报名丨Computer useVoice Agent :使用 TEN 搭建你的 Mac Assistant
  • error: conflicting types for ‘SSL_SESSION_get_master_key’
  • jmeter--参数化
  • vue2和vue3储存组件
  • 学习笔记-人脸识别相关编程基础
  • 14、deepseek视觉大模型Janus Pro本地部署及实战
  • WSL Ubuntu 安装 CUDA 教程
  • 【NLP251】命名实体识别常用模块(基于Transformer分类)
  • 从驾驶员到智能驾驶:汽车智能化进程中的控制与仿真技术
  • 【JavaScript】《JavaScript高级程序设计 (第4版) 》笔记-Chapter12-BOM
  • HBASE面试技巧
  • 洛谷 acwing刷题 有关图的存储形式和djstra算法的例题
  • C语言进阶习题(4结构体)【1】通讯录的实现
  • 从无序到有序:上北智信通过深度数据分析改善会议室资源配置
  • 企业网站设计HTML源码模板
  • 【认证授权FAQ】HP Anyware LLS服务器常用命令