本文为 工作用Go: 异步任务怎么写 系列的第1篇
在响应应用请求的过程中, 有时候会遇到比较耗时的任务, 比如给用户发送邮件, 耗时任务时间不可能控, 很可能超过 1s, 为了给用户比较好的体验, 一般会控制请求响应时间(RT, response time)在 300ms 内(不考虑网络波动), 甚至在 200ms 内. 面对这样的工作场景, 就需要使用异步任务进行处理.
从一段简单的代码开始:
funcTestTask(t*testing.T) { task() log.Print("req done") } functask() { // 模拟耗时任务time.Sleep(time.Second) log.Print("task done") }
- 代码在 Goland 中编写, 同时也推荐使用 Goland 进行 Go 开发
- 这里使用单测(
test
)演示代码:
- 输入
test
就可以快速生成代码(Goland 中称之为live templates
, 其实就是预设好的代码片段) - 在单测点击可以执行: 1. 点击左侧(gutter icon)的运行图标; 2. 函数上右键菜单键; 3. 快捷键
ctl-shift-R
上面使用 task()
模拟耗时 1s 的任务, 整个test代表一次请求, 执行如下:
===RUNTestTask2022/11/1720:11:15taskdone2022/11/1720:11:15reqdone---PASS: TestTask (1.00s) PASS
Go基础知识: 天生并发, 使用
go
关键字就可以开新协程, 将代码放到新协程中执行
funcTestTask(t*testing.T) { gotask() log.Print("req done") } functask() { // 模拟耗时任务time.Sleep(time.Second) log.Print("task done") }
- 只需要在
task()
前添加go
关键字, 就可以新开一个协程, 将task()
在新协程中执行
不过在这里, 并没有得到预期的结果:
===RUNTestTask2022/11/1720:16:08reqdone---PASS: TestTask (0.00s) PASS
- 输出显示:
task()
中的日志没有输出, 看起来像没有执行
Go基础知识: Go的代码都在协程中执行, 入口
main()
函数是主协程, 之后使用go
关键词开的协程都是子协程, 主协程退出后, 程序会终止(exit)
也就是说上面的 TestTask()
(主协程) 和 go task()
(子协程)都执行了, 但是主协程执行完, 程序退出了, 子协程没执行完(或者没调度到), 就被强制退出了