Go语言异步模式相关问题:同步执行DB查询是否会阻塞线程及有无对应方案
核心结论
这种同步执行DB查询的写法是Go生态的常规实现方式,并不会出现你担心的阻塞整个OS线程的问题。
具体原因说明
- 首先要明确Go的M:N调度模型的特性:你在代码里看到的「同步阻塞」只是针对当前goroutine而言的,当
db.Exec触发IO等待时,Go runtime会自动把当前goroutine挂起,将其绑定的OS线程腾出来运行其他就绪状态的goroutine,等DB请求返回后,当前goroutine才会被重新调度执行,底层本质还是非阻塞IO,完全不会浪费OS线程资源。 - Go的设计思路就是把异步IO的复杂度封装在runtime层面,开发者只需要写同步逻辑就能拿到异步的性能收益,不需要像Node.js那样编写回调、Promise、async/await风格的异步代码,避免了回调地狱、异步异常处理等额外的心智负担。
- 如果你确实需要显式的异步控制能力(比如并行执行多个DB查询减少总耗时),可以通过
goroutine + channel的模式实现,示例代码如下:
type QueryResult struct { Data interface{} Err error } // 启动goroutine异步执行两个查询 resCh := make(chan QueryResult, 2) go func() { res, err := db.Exec(stmt1, title, content) resCh <- QueryResult{Data: res, Err: err} }() go func() { res, err := db.Query(stmt2, author) resCh <- QueryResult{Data: res, Err: err} }() // 等待两个查询返回,总耗时为耗时更长的那个查询的耗时 res1 := <-resCh res2 := <-resCh
- 补充说明:标准库的
database/sql包内置了连接池,默认支持并发调用,只要根据业务场景合理配置SetMaxOpenConns、SetMaxIdleConns等连接池参数,直接在http handler里写同步DB查询的性能完全可以满足绝大多数场景的需求,不需要额外做异步改造。
内容的提问来源于stack exchange,提问作者Elnur
相关产品推荐
相关产品推荐

