c := make(chanint) deferclose(c) gofunc() { c <- 10 }() fmt.Println(<-c)
上述往Channel c中发送10,然后从c中取出。如果没有发送任何数据,那么c会一直block
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
funcsum(a []int, c chanint) { total := 0 for _, v := range a { total += v } c <- total }
functestSum() { s := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} c := make(chanint, 10) deferclose(c) go sum(s[:len(s)/2], c) go sum(s[len(s)/2:], c) x, y := <-c, <-c fmt.Println(x, y, x+y) }
上诉x, y会一直等到sum函数中的值算完并发送到c中
1 2 3 4 5 6 7 8 9 10 11
c := make(chanint) gofunc() { deferclose(c) for i := 0; i < 10; i++ { c <- i } }()
funcfibonacci(c, quit chanint) { deferclose(c) x, y := 1, 1 for { select { case c <- x: x, y = y, x+y case <-time.After(5 * time.Second): println("timeout") break case <-quit: fmt.Println("quit") return } } }
c := make(chanint) quit := make(chanint) gofunc() { for i := 0; i < 10; i++ { fmt.Println(<-c) } quit <- 0 }() fibonacci(c, quit)
// lock protects all fields in hchan, as well as several // fields in sudogs blocked on this channel. // // Do not change another G's status while holding this lock // (in particular, do not ready a G), as this can deadlock // with stack shrinking. lock mutex //锁,用于保护上述所有字段 }
type waitq struct { first *sudog last *sudog }
type sudog struct { // The following fields are protected by the hchan.lock of the // channel this sudog is blocking on. shrinkstack depends on // this for sudogs involved in channel ops.
g *g
// isSelect indicates g is participating in a select, so // g.selectDone must be CAS'd to win the wake-up race. isSelect bool next *sudog prev *sudog elem unsafe.Pointer // data element (may point to stack)
// The following fields are never accessed concurrently. // For channels, waitlink is only accessed by g. // For semaphores, all fields (including the ones above) // are only accessed when holding a semaRoot lock.
acquiretime int64 releasetime int64 ticket uint32 parent *sudog // semaRoot binary tree waitlink *sudog // g.waiting list or semaRoot waittail *sudog // semaRoot c *hchan // channel }
// compiler checks this but be safe. if elem.size >= 1<<16 { throw("makechan: invalid channel element type") } if hchanSize%maxAlign != 0 || elem.align > maxAlign { throw("makechan: bad alignment") }
if size < 0 || uintptr(size) > maxSliceCap(elem.size) || uintptr(size)*elem.size > maxAlloc-hchanSize { panic(plainError("makechan: size out of range")) }
// Hchan does not contain pointers interesting for GC when elements stored in buf do not contain pointers. // buf points into the same allocation, elemtype is persistent. // SudoG's are referenced from their owning thread so they can't be collected. // TODO(dvyukov,rlh): Rethink when collector can move allocated objects. var c *hchan switch { case size == 0 || elem.size == 0: // Queue or element size is zero. c = (*hchan)(mallocgc(hchanSize, nil, true)) // Race detector uses this location for synchronization. c.buf = unsafe.Pointer(c) case elem.kind&kindNoPointers != 0: // Elements do not contain pointers. // Allocate hchan and buf in one call. c = (*hchan)(mallocgc(hchanSize+uintptr(size)*elem.size, nil, true)) c.buf = add(unsafe.Pointer(c), hchanSize) default: // Elements contain pointers. c = new(hchan) c.buf = mallocgc(uintptr(size)*elem.size, elem, true) }
/* * generic single channel send/recv * If block is not nil, * then the protocol will not * sleep but return if it could * not complete. * * sleep can wake up with g.param == nil * when a channel involved in the sleep has * been closed. it is easiest to loop and re-run * the operation; we'll see that it's now closed. */ funcchansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr)bool { if c == nil { if !block { returnfalse } gopark(nil, nil, "chan send (nil chan)", traceEvGoStop, 2) throw("unreachable") }
if debugChan { print("chansend: chan=", c, "\n") }
if raceenabled { racereadpc(unsafe.Pointer(c), callerpc, funcPC(chansend)) }
// Fast path: check for failed non-blocking operation without acquiring the lock. // // After observing that the channel is not closed, we observe that the channel is // not ready for sending. Each of these observations is a single word-sized read // (first c.closed and second c.recvq.first or c.qcount depending on kind of channel). // Because a closed channel cannot transition from 'ready for sending' to // 'not ready for sending', even if the channel is closed between the two observations, // they imply a moment between the two when the channel was both not yet closed // and not ready for sending. We behave as if we observed the channel at that moment, // and report that the send cannot proceed. // // It is okay if the reads are reordered here: if we observe that the channel is not // ready for sending and then observe that it is not closed, that implies that the // channel wasn't closed during the first observation. if !block && c.closed == 0 && ((c.dataqsiz == 0 && c.recvq.first == nil) || (c.dataqsiz > 0 && c.qcount == c.dataqsiz)) { returnfalse }
var t0 int64 if blockprofilerate > 0 { t0 = cputicks() }
//锁住当前状态 lock(&c.lock)
//如果当前channel已经关闭,那么直接抛异常 if c.closed != 0 { unlock(&c.lock) panic(plainError("send on closed channel")) }
//发现有阻塞的读协程 if sg := c.recvq.dequeue(); sg != nil { // Found a waiting receiver. We pass the value we want to send // directly to the receiver, bypassing the channel buffer (if any). send(c, sg, ep, func() { unlock(&c.lock) }, 3) returntrue }
//还有可用的缓存空间 if c.qcount < c.dataqsiz { // Space is available in the channel buffer. Enqueue the element to send. qp := chanbuf(c, c.sendx) if raceenabled { raceacquire(qp) racerelease(qp) } typedmemmove(c.elemtype, qp, ep) c.sendx++ if c.sendx == c.dataqsiz { c.sendx = 0 } c.qcount++ unlock(&c.lock) returntrue }
if !block { unlock(&c.lock) returnfalse }
//当前缓存已满,阻塞当前routine // Block on the channel. Some receiver will complete our operation for us. gp := getg() mysg := acquireSudog() mysg.releasetime = 0 if t0 != 0 { mysg.releasetime = -1 } // No stack splits between assigning elem and enqueuing mysg // on gp.waiting where copystack can find it. mysg.elem = ep mysg.waitlink = nil mysg.g = gp mysg.isSelect = false mysg.c = c gp.waiting = mysg gp.param = nil c.sendq.enqueue(mysg) goparkunlock(&c.lock, "chan send", traceEvGoBlockSend, 3)
// someone woke us up. if mysg != gp.waiting { throw("G waiting list is corrupted") } gp.waiting = nil if gp.param == nil { if c.closed == 0 { throw("chansend: spurious wakeup") } panic(plainError("send on closed channel")) } gp.param = nil if mysg.releasetime > 0 { blockevent(mysg.releasetime-t0, 2) } mysg.c = nil releaseSudog(mysg) returntrue }
首先判断chan是否为空.如果为空,那么会使当前的goroutine进入休眠状态。然而go启动时会检测系统的运行状态。在这里其发现发数据的goroutine和收数据的goroutine都进入了休眠状态,那么系统会直接报错 all goroutines are asleep - deadlock!
// chanrecv receives on channel c and writes the received data to ep. // ep may be nil, in which case received data is ignored. // If block == false and no elements are available, returns (false, false). // Otherwise, if c is closed, zeros *ep and returns (true, false). // Otherwise, fills in *ep with an element and returns (true, true). // A non-nil ep must point to the heap or the caller's stack. funcchanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) { // raceenabled: don't need to check ep, as it is always on the stack // or is new memory allocated by reflect.
if debugChan { print("chanrecv: chan=", c, "\n") }
if c == nil { if !block { return } gopark(nil, nil, "chan receive (nil chan)", traceEvGoStop, 2) throw("unreachable") }
// Fast path: check for failed non-blocking operation without acquiring the lock. // // After observing that the channel is not ready for receiving, we observe that the // channel is not closed. Each of these observations is a single word-sized read // (first c.sendq.first or c.qcount, and second c.closed). // Because a channel cannot be reopened, the later observation of the channel // being not closed implies that it was also not closed at the moment of the // first observation. We behave as if we observed the channel at that moment // and report that the receive cannot proceed. // // The order of operations is important here: reversing the operations can lead to // incorrect behavior when racing with a close. if !block && (c.dataqsiz == 0 && c.sendq.first == nil || c.dataqsiz > 0 && atomic.Loaduint(&c.qcount) == 0) && atomic.Load(&c.closed) == 0 { return }
var t0 int64 if blockprofilerate > 0 { t0 = cputicks() }
lock(&c.lock)
//没有数据 if c.closed != 0 && c.qcount == 0 { if raceenabled { raceacquire(unsafe.Pointer(c)) } unlock(&c.lock) if ep != nil { typedmemclr(c.elemtype, ep) } returntrue, false }
//有阻塞的写队列。则直接接受数据 if sg := c.sendq.dequeue(); sg != nil { // Found a waiting sender. If buffer is size 0, receive value // directly from sender. Otherwise, receive from head of queue // and add sender's value to the tail of the queue (both map to // the same buffer slot because the queue is full). recv(c, sg, ep, func() { unlock(&c.lock) }, 3) returntrue, true }
//直接从队列中取数据 if c.qcount > 0 { // Receive directly from queue qp := chanbuf(c, c.recvx) if raceenabled { raceacquire(qp) racerelease(qp) } if ep != nil { typedmemmove(c.elemtype, ep, qp) } typedmemclr(c.elemtype, qp) c.recvx++ if c.recvx == c.dataqsiz { c.recvx = 0 } c.qcount-- unlock(&c.lock) returntrue, true }
if !block { unlock(&c.lock) returnfalse, false }
//缓冲为空,阻塞当前goroutine // no sender available: block on this channel. gp := getg() mysg := acquireSudog() mysg.releasetime = 0 if t0 != 0 { mysg.releasetime = -1 } // No stack splits between assigning elem and enqueuing mysg // on gp.waiting where copystack can find it. mysg.elem = ep mysg.waitlink = nil gp.waiting = mysg mysg.g = gp mysg.isSelect = false mysg.c = c gp.param = nil c.recvq.enqueue(mysg) goparkunlock(&c.lock, "chan receive", traceEvGoBlockRecv, 3)
// someone woke us up if mysg != gp.waiting { throw("G waiting list is corrupted") } gp.waiting = nil if mysg.releasetime > 0 { blockevent(mysg.releasetime-t0, 2) } closed := gp.param == nil gp.param = nil mysg.c = nil releaseSudog(mysg) returntrue, !closed }
// release all readers for { sg := c.recvq.dequeue() if sg == nil { break } if sg.elem != nil { typedmemclr(c.elemtype, sg.elem) sg.elem = nil } if sg.releasetime != 0 { sg.releasetime = cputicks() } gp := sg.g gp.param = nil if raceenabled { raceacquireg(gp, unsafe.Pointer(c)) } gp.schedlink.set(glist) glist = gp }
// release all writers (they will panic) for { sg := c.sendq.dequeue() if sg == nil { break } sg.elem = nil if sg.releasetime != 0 { sg.releasetime = cputicks() } gp := sg.g gp.param = nil if raceenabled { raceacquireg(gp, unsafe.Pointer(c)) } gp.schedlink.set(glist) glist = gp } unlock(&c.lock)
// Ready all Gs now that we've dropped the channel lock. for glist != nil { gp := glist glist = glist.schedlink.ptr() gp.schedlink = 0 goready(gp, 3) } }
上述代码就定义了一个go的接口,包含了一个方法。当然也可以不包含方法。go的interface是一种具有一组方法的类型。如果一个类型实现了一个interface的所有方法,我们就说该类型实现了该接口。其实go中所有的类型都实现了empty interface。go不需要使用关键字来实现interface,只需要实现interface包含的方法即可。上述代码struct S实现了interface I
var dataSlice []int = foo() var interfaceSlice []interface{} = make([]interface{}, len(dataSlice)) for i, d := range dataSlice { interfaceSlice[i] = d }
privatebooleandeduceWebEnvironment() { for (String className : WEB_ENVIRONMENT_CLASSES) { if (!ClassUtils.isPresent(className, null)) { returnfalse; } } returntrue; } publicstaticbooleanisPresent(String className, ClassLoader classLoader) { try { forName(className, classLoader); returntrue; } catch (Throwable ex) { // Class or one of its dependencies is not present... returnfalse; } }
// Add boot specific singleton beans context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { context.getBeanFactory().registerSingleton("springBootBanner", printedBanner); }
// Load the sources Set<Object> sources = getSources(); Assert.notEmpty(sources, "Sources must not be empty"); load(context, sources.toArray(newObject[sources.size()])); listeners.contextLoaded(context); }
准备上下文
1 2 3 4 5 6 7 8 9 10 11
privatevoidrefreshContext(ConfigurableApplicationContext context) { refresh(context); if (this.registerShutdownHook) { try { context.registerShutdownHook(); } catch (AccessControlException ex) { // Not allowed in some environments. } } }