上篇说到了,http 服务可以检测客户端异常终止的事件。通过 select 监听 context.Done(),可以终止不必要的数据库查询,节约资源。 这次聊下,何时使用 context.WithCancel ?
下面的代码,是个 context 调用链。父-->子-->子子-->子子子-->子子子子结构。通过不停的派生新的 context 生成后代。我们可以调整 failId 控制父还是子子提前退出。
比如 testContext(1, 3) 生成 3 个 context,第 2 个退出。
func testContext(failId int, max int) {
ctxs := make([]context.Context, 0, max)
cancels := make([]func(), 0, max)
var (
ctx context.Context
cancel func()
wg sync.WaitGroup
)
for i := 0; i < max; i++ {
if i == 0 {
ctx, cancel = context.WithCancel(context.Background())
} else {
ctx, cancel = context.WithCancel(ctxs[i-1])
}
ctxs = append(ctxs, ctx)
cancels = append(cancels, cancel)
}
wg.Add(max)
defer wg.Wait()
for i := 0; i < max; i++ {
go func(id int) {
defer wg.Done()
if id == failId {
cancels[id]()
}
select {
case <-ctxs[id].Done():
}
}(i)
}
}
你惊奇的发现,只有第 2 个(index 为 1 )以及他的后代退出。我们随意修改 failId 都是这个结论。父 context 会影响他的后代,但是后代挂了不影响父辈。
这里,希望 http.context 的事件影响到数据库里面,但不希望数据库里面通过黑科技把事件影响到 http。就派生一个新的。 在 gin.Context。c.Request 是*http.Request 对象,改对象有个 Context()方法返回 context,传递给 db.QueryContext 函数
package main
import (
"context"
"database/sql"
"github.com/gin-gonic/gin"
_ "github.com/go-sql-driver/mysql"
"log"
)
func main() {
db, err := sql.Open("mysql", "root:123456@tcp(192.168.5.17)/test")
if err != nil {
log.Printf("err:%s\n", err)
return
}
defer db.Close()
r := gin.Default()
r.POST("/test", func(c *gin.Context) {
// 从 http.Client 派生一个新的 context
ctx, cancel := context.WithCancel(c.Request.Context())
defer cancel()
rows, err := db.QueryContext(ctx, "select * from test")
if err != nil {
c.JSON(200, gin.H{"errcode": 0xff, "errmsg": err.Error()})
return
}
names := make([]string, 0, 3)
for rows.Next() {
var name string
rows.Scan(&name)
if err != nil {
break
}
names = append(names, name)
}
if closeErr := rows.Close(); closeErr != nil {
c.JSON(200, gin.H{"errcode": 0xff, "errmsg": closeErr.Error()})
return
}
c.JSON(200, gin.H{"errcode": 0, "errmsg": "ok", "names": names})
})
r.Run()
}
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.