并发版schedule的select是不是会导致crash?
来源:16-4 队列实现调度器

慕哥4405024
2018-11-08
老师,看了并发版的schedule的代码有一个疑问,代码如下:
func (s *QueuedScheduler) Run() {
s.workerChan = make(chan chan engine.Request)
s.requestChan = make(chan engine.Request)
go func() {
var requestQ []engine.Request
var workerQ []chan engine.Request
for {
var activeRequest engine.Request
var activeWorker chan engine.Request
if len(requestQ) > 0 &&
len(workerQ) > 0 {
activeWorker = workerQ[0]
activeRequest = requestQ[0]
}
select {
case r := <-s.requestChan:
requestQ = append(requestQ, r)
case w := <-s.workerChan:
workerQ = append(workerQ, w)
case activeWorker <- activeRequest:
//这个case中,如果schedule工作了一段时间后,某一时刻requestQ先变为0,
activeRequest保留的应该是最后一个request,
这个request对应一个worker channel被保留在activeWorker中,
当activeWorker 完成的时候,select会从这个case返回吧,
activeWorker 得到的还是最后的activeRequest。但是我们看下面的代码,
requestQ = requestQ[1:]这个不是要crash?
workerQ = workerQ[1:]
requestQ = requestQ[1:]
}
}
}()
}
写回答
1回答
-
ccmouse
2018-11-11
不会crash的。
我们的并发是多个goroutine会并发。在单个goroutine内,一定是顺序执行的。我们的requestQ是一个局部变量,这个局部变量只会被这一个goroutine操作,没有人会并发的改变它。
我们看到进入case activeWorker <- activeRequest:的前提是len(requestQ) > 0,所以后面一定可以requestQ = requestQ[1:]。
那么不同的goroutine之间怎么同步的呢?通过channel,这就是为什么我们有了requestChan,还要用一个局部变量requestQ来排队。
这个例子正是说明了go语言的csp模型通过(使用channel)通信来共享数据,而不是传统意义上的使用共享数据(比如Queue+Lock)来通信。
022018-11-13
相似问题