@
RedisMasterNode @
Nazz @
leonshaw 不是的,wait group 只能在所有任务完成前一直阻塞住。而作为一个 spawner ,你需要时刻维护一个有长度的队列,当队列空出来时立即解除正在预约( schedule )任务的 routine 的阻塞,wait group 显然不合适。
注意我们的目标是,让结果按照添加的顺序依次输出,而不是一次性等待所有的结果一起输出。
有异步语法的语言,在这个场景的做法是
- 一个有长度的阻塞队列
- 当外界 scheduling 新任务时,spwaner 向队列获取一个空槽,如果队列已满,那么 spanwer 和 请求者都会被阻塞
- 如果获取了空槽,将任务放入空槽,获得一个 promise
- 创建新 promise, 在这个 promise 里 { await 任务队列的尾部任务(因为我们需要按任务的添加顺序而不是任务完成顺序来返回),await 到之后返回上一步获得的 promise }
- 把上面这个 promise 加到 out 队列里,每次提取结果时 await out 队列的头部
而 golang 要模拟这个做法的话,首先它没有 promise ,也没有 goroutine 的 handler ,然后要实现跟上述等价的 spawner 必须使所有调用 spanwer 的线程共享同一个 channel ,意味着 chan 要么是全局的,要么扔到 context 里。先简单考虑全局唯一 chan 的做法。(但复制 chan 用 context 传这种逆天玩意我也写过)
提取任务槽这步没问题,但怎么模拟一个 promise ?
- c := make(chan,1) ; go func(){c<-do();)}
那怎么获取任务队列的尾部任务并 await 它?
- 如果任务队列只是个简单的 channel 是做不到的,因此需要一个 slice + channel ,可是 slice 就没有锁了,你这时候要考虑一个可阻塞环境( chan )下的锁问题,头开始疼起来了
怎么返回 await 了 c 的新 promise ?
- ……
对了,这个新 promise 还要放到 out 队列里
- …………