funcmain() { go a() go b() select {} // prevent the program from terminating, ignore for now } funca() { go aa() go ab() } funcaa() { println("aa") } funcab() { println("ab") }
funcb() { go ba() go bb() } funcba() { println("ba") } funcbb() { println("bb") }
运行 go run main.go 会输出:
1 2 3 4 5 6 7 8 9 10 11
❯ go run main.go bb ba ab aa fatal error: all goroutines are asleep - deadlock!
goroutine 1 [select (no cases)]: main.main() mani.go:6 +0x52 exit status 2
defdequeue(self, x=None): if x isNone: x = self.pop(0) WaitingQueue.total -= 1 else: idx = self.index(x) if idx isnotNone: self.pop(idx) WaitingQueue.total -= 1 return x
while execution_queue: # 进入执行循环 f = execution_queue.pop(0) f() if WaitingQueue.total > 0: # 如果执行队列已经空了,但是还有在等待的任务,就会形成 deadlock raise RuntimeError("fatal error: all goroutines are asleep - deadlock")
defsend(chan, value, callback): """ Go's Spec: Communication blocks until the send can proceed. A send on an unbuffered channel can proceed if a receiver is ready. [...] A send on a closed channel proceeds by causing a run-time panic. A send on a nil channel blocks forever. """ # Nil chan 直接返回 if chan isNone: WaitingQueue.total += 1 return # chan 关闭,panic if chan.closed: raise RuntimeError("panic: send on closed channel") # 有接受请求,处理 if chan.waiting_to_recv: receiver = chan.waiting_to_recv.dequeue() go(callback) go(lambda: receiver(value, True)) return
defrecv(channel, callback): """ Go's Spec: The expression blocks until a value is available. Receiving from a nil channel blocks forever. A receive operation on a closed channel can always proceed immediately, yielding the element type's zero value after any previously sent values have been received. """ # "Receiving from a nil channel blocks forever." if channel isNone: WaitingQueue.total += 1 return
# "if anything is currently blocked on sending for this channel, receive it" if channel.waiting_to_send: value, sender = channel.waiting_to_send.dequeue() go(lambda: callback(value, True)) go(sender) return
# "A receive operation on a closed channel can always proceed immediately, # yielding the element type's zero value after any previously sent values have been received." if channel.closed: go(lambda: callback(None, False)) return
channel.waiting_to_recv.enqueue(callback)
defclose(channel): # if the channel is already closed, we panic if channel.closed: raise Exception("close of closed channel")
channel.closed = True
# complete any senders while channel.waiting_to_send: value, callback = channel.waiting_to_send.dequeue() send(channel, value, callback)
# complete any receivers while channel.waiting_to_recv: callback = channel.waiting_to_recv.dequeue() recv(channel, callback)
# first see if any of the cases are ready to proceed ready = [caseforcasein cases if is_ready(case)] if ready: # pick a random one case = ready[randint(0, builtins.len(ready)-1)] ifcase[0] == send: send(case[1], case[2], case[3]) elifcase[0] == recv: recv(case[1], case[2]) go(callback) return
# next see if there's a default case defaults = [caseforcasein cases ifcase[0] == default] if defaults: defaults[0]() go(callback) return
# finally we will enqueue each case into the waiting queues # we also update each callback so it will cleanup all the # other cases so only one is fired