go - 进行常规泄漏修复
问题描述
我目前正在从事一项小型服务。根据我的测试,我编写的代码在与上下文相关的某些情况下可能会泄漏 go 例程。有没有一种好的和/或惯用的方法来解决这个问题?我在下面提供了一些示例代码。
func Handle(ctx context.Context, r *Req) (*Response, error) {
ctx, cancel := context.WithTimeout(ctx, time.Second * 5)
defer cancel()
resChan := make(chan Response)
errChan := make(chan error)
go process(r, resChan, errChan)
select {
case ctx.Done():
return nil, ctx.Err()
case res := <-resChan:
return &res, nil
case err := <-errChan:
return nil, err
}
}
func process(r *Req, resChan chan<- Response, errChan chan<- error) {
defer close(errChan)
defer close(resChan)
err := doSomeWork()
if err != nil {
errChan <- err
return
}
err = doSomeMoreWork()
if err != nil {
errChan <- err
return
}
res := Response{}
resChan <- res
}
假设,如果客户端取消上下文或超时发生在进程 func 有机会在无缓冲通道之一(resChan,errChan)上发送之前,Handle 将没有通道读取器,并且通道上的发送将无限期阻塞没有读者。由于在这种情况下进程不会返回,因此通道也不会关闭。
我提出了 process2 作为解决方案,但我不禁认为我做错了什么,或者有更好的方法来处理这个问题。
func process2(ctx context.Context, r *Req, resChan chan<- Response, errChan chan<- error) {
defer close(errChan)
defer close(resChan)
err := doSomeWork()
select {
case <-ctx.Done():
return
default:
if err != nil {
errChan <- err
return
}
}
err = doSomeMoreWork()
select {
case <-ctx.Done():
return
default:
if err != nil {
errChan <- err
return
}
}
res := Response{}
select{
case <-ctx.Done():
return
default:
resChan <- res
}
}
这种方法确保每次尝试发送通道时,首先检查上下文是否已完成或取消。如果是,则它不会尝试发送并返回。我很确定这修复了第一个进程函数中发生的任何 goroutine 泄漏。
有没有更好的办法?也许我错了。
解决方案
推荐阅读
- javascript - 将 innerText 设置为一个变量,但它不会改变
- css - 带有 mapbox gl js 的 CSS 布局
- c# - Hangfire 仪表板页面显示 404
- azure-devops - Azure DevOps 中发布管道的测试服务器
- firebase - 看起来您正在尝试访问 functions.config().algolia 但那里没有任何价值
- vuejs2 - Vuetify - 关闭没有 v-dialog 的菜单对话框(使用激活器)
- python - 使用 Pandas MultiIndex 选择多行分层 DataFrame
- c# - SuppressMessage 不考虑 Resharper 的 MessageId
- python - 如何删除一元 +: 'str' 的错误错误操作数类型。在我的循环句子中
- java - 为什么这总是返回正分数?简单的代码