什么时候应该使用goroutine?通过Redis IO操作示例验证用法正确性
结论
你的理解不完全正确,你给出的示例场景下,这种goroutine写法反而比直接调用性能更差,没有任何优势。
为什么你的示例没有收益
你写的goroutine版本逻辑是:开新goroutine执行Redis请求,主goroutine立刻阻塞等待channel返回结果。和直接在主goroutine执行Redis请求的逻辑完全一致,本质都是全程阻塞等待IO返回,反而多了以下不必要的开销:
- 创建goroutine的调度开销
- 创建channel、跨goroutine传递数据的通信开销
- 额外的内存占用
什么时候用goroutine处理IO才更优
只有当你有多个可并行执行的IO任务时,goroutine才能发挥价值。
举个例子,如果你需要同时查询3个不同的Redis key,两种写法的耗时差距会非常明显:
- 顺序查询:总耗时 = 查key1耗时 + 查key2耗时 + 查key3耗时
- 并行查询(3个goroutine分别查):总耗时 = 三个查询中最慢的那个的耗时
并行查询的示例代码如下:
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() ch := make(chan string, 3) keys := []string{"key1", "key2", "key3"} // 开3个goroutine并行查 for _, key := range keys { go func(k string) { res, err := redis.Get(ctx, k).Result() if err != nil { // 按需处理错误 res = "" } ch <- res }(key) } // 收集结果 results := make([]string, 0, 3) for i := 0; i < 3; i++ { results = append(results, <-ch) }
额外注意事项
你给出的示例代码还有两个风险点需要注意:
- 忽略了错误处理,Redis请求可能超时、失败,直接忽略错误会导致后续逻辑拿到空值也无法感知问题
- 没有加context超时控制,如果Redis请求卡住,goroutine会永久阻塞,造成goroutine泄漏,请求量上来后会把进程资源耗尽
内容的提问来源于stack exchange,提问作者Qing Qi
相关产品推荐
相关产品推荐

