Go使用chan或context退出协程

简介: Go使用chan或context退出协程

问题

go两个协程使用了同一个文件句柄,其中一个协程关闭了这个文件句柄并退出了协程,如何及时通知另一个协程退出?

分析

当一个协程关闭了这个文件对象后,底层文件的文件描述符就会被释放。

这个时候,另一个协程还持有着同一个文件对象,但其实对应的文件描述符已经不存在了。

所以当第二个协程通过这个文件对象再对文件进行操作的时候,例如读写文件等,就会发生异常,比如文件描述符不存在错误等。

解决

为了避免这个问题,共享文件对象的多个协程需要通过一个通道或锁进行协调:

每个协程在使用文件对象前需要获得锁或从通道接收通知。

最后关闭文件对象的协程在关闭后,通过通道或解锁来通知其他协程对象已经无效。

其他协程收到通知后,就不再对这个已关闭的文件对象进行操作。

1. 使用 channel 通道

在主协程中,可以定义一个 channel,用来通知其它协程退出。协程在执行时可以监听这个 channel,一旦接收到退出通知,就可以进行清理工作,并退出协程。

quit := make(chan bool)

go func() {
   
    defer fmt.Println("Goroutine exit")
    for {
   
        select {
   
        case <-quit:
            return
        default:
            // ...
        }
    }
}()

// 主协程中发送退出通知
quit <- true

2. 使用 context 包

Go 语言标准库中提供了 context 包,可以用来控制协程的生命周期。

在主协程中可以创建一个 context 对象,并将其传递给协程,然后调用 cancel 方法,通知所有协程退出。

context.Background() 是 Go 上下文系统中一个重要的初始预定义上下文值,代表了一个没有截止时间限制的空上下文环境。

1.使用WithCancel函数创建上下文和取消函数

ctx, cancel := context.WithCancel(context.Background())

go func(ctx context.Context) {
   
    for {
   
        select {
   
        case <-ctx.Done():
            fmt.Println("exit")
            return
        default:
            // 执行一些耗时的操作
            time.Sleep(1 * time.Second)
            fmt.Println("running")
        }
    }
}(ctx)

time.Sleep(5 * time.Second)
// cancel()
fmt.Println("cancelled")
time.Sleep(1 * time.Second)

2.使用Deadline超时结束协程

ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Second))

3.使用WithTimeout限定操作时间

ctx, cancel := context.WithTimeout(context.Background(), time.Second)
目录
相关文章
|
2月前
|
Go 调度 开发者
[go 面试] 深入理解进程、线程和协程的概念及区别
[go 面试] 深入理解进程、线程和协程的概念及区别
|
3月前
|
Java Go 调度
GO 协程
GO 协程
30 0
|
4月前
|
Go
go语言并发编程(五) ——Context
go语言并发编程(五) ——Context
|
2月前
|
缓存 前端开发 Go
go中的chan管道机制
Go 语言推崇通过通信来共享内存而非共享内存来通信,其中 Channel(通常简写为 `chan`)作为关键机制之一,允许两个并发执行的协程之间进行同步和数据交换。`chan` 是一种引用类型,可通过 `make` 函数创建,
|
2月前
|
监控 Devops 测试技术
|
2月前
|
存储 SQL Go
一文弄懂Go语言的Context包,值得收藏!
在开发高效的Go应用程序时,处理超时、取消操作和传递请求范围的数据至关重要。Go标准库中的`context`包提供了一套强大的工具,用于在不同层级间传递取消信号、超时和截止时间等信息。本文首先概述了`context`包的核心功能,接着详细介绍了关键方法,如`WithCancel`、`WithDeadline`、`WithTimeout`和`WithValue`的使用场景。通过创建和派生上下文,开发者能更好地管理请求的生命周期,控制长时间运行的操作,并在并发环境中传递必要的数据。
38 1
|
2月前
|
人工智能 Go
Go 等待协程完成
Go 等待协程完成
24 0
|
2月前
|
存储 缓存 Java
深入理解 go chan
深入理解 go chan
35 0
|
4月前
|
Go
如何在Go中进行文件操作以及如何使用协程来实现并发编程
如何在Go中进行文件操作以及如何使用协程来实现并发编程
45 2
|
5月前
|
安全 Go 调度