In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-17 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/02 Report--
This article introduces the relevant knowledge of "what is the implementation mechanism of simpread golang and select case". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!
1.1 chan operating rules 1
When a goroutine is about to receive data from a non-nil & non-closed chan, goroutine first acquires the lock on the chan, and then does the following until a condition is met:
1) if the value buffer on the chan is not empty, it also means that the recv goroutine queue on the chan must also be empty, and the receiving goroutine will unshift a value from the value buffer. At this time, if the send goroutine queue is not empty, because a location has been vacated in the value buffer just now, it will unshift a sending goroutine from the send goroutine queue and let it resume execution, and let it perform the operation of writing data to the chan. In fact, it is to restore the sending goroutine execution and push the data to be sent by the sending goroutine to the value buffer. Then, it is time to receive the goroutine and get the data, so continue to execute. In this scenario, the receive operation of the channel is called the non-blocking operation.
2) on the other hand, if the value buffer is empty, but the send goroutine queue is not empty, in this case, the chan must be unbufferred chan, otherwise the value buffer must have data. At this time, the receiving goroutine will unshift a sending goroutine from the send goroutine queue and receive the data to be sent by the sending goroutine (two goroutine has a sending data address and one has a receiving data address, so copy it and ok it). Then the outgoing sending goroutine will resume execution, and the receiving goroutine can continue to execute. In this case, the chan receive operation is also a non-blocking operation.
3) on the other hand, if both value buffer and send goroutine queue are empty and there is no data to receive, the received goroutine will be transferred to the recv goroutine queue of chan, and the received goroutine will be transferred to the blocking state. When will the recovery period be executed until a goroutine tries to send data to chan. In this scenario, the chan receive operation is a blocking operation.
1.2 chan operating rules 2
When a goroutine common sense sends data to a non-nil & non-closed chan, the goroutine will first try to acquire the lock on the chan and then do the following until one of the cases is satisfied.
1) if the recv goroutine queue of the chan is not empty, in this case, the value buffer must be empty. Sending goroutine will unshift a recv goroutine from recv goroutine queue, then directly copy the data you want to send to the receiving address of the recv goroutine, and then resume the operation of the recv goroutine, and the current sending goroutine will continue to execute. In this case, the chan send operation is a non-blocking operation.
2) if the recv goroutine queue of the chan is empty and the value buffer is dissatisfied, in this case, the send goroutine queue must be empty, because the value buffer is dissatisfied that the goroutine can be sent and cannot be blocked. The data to be transmitted by the transmitting goroutine is push to the value buffer and execution continues. In this case, the chan send operation is a non-blocking operation.
3) if the recv goroutine queue of the chan is empty and the value buffer is full, the sending goroutine will be push into the send goroutine queue to enter the blocking state. Wait until another goroutine attempts to receive data from the chan before it can be awakened to resume execution. In this case, the chan send operation is a blocking operation.
1.3 chan operating rules 3
When a goroutine tries to close a non-nil & non-closed chan, the close operation will do the following in turn.
1) if the recv goroutine queue of the chan is not empty, the value buffer must be empty, because if the value buffer is not empty, it will continue to receive data from the goroutine in the unshift recv goroutine queue until the value buffer is empty (here you can take a look at the chan send operation. Before chan send writes the data, it must unshift a recv goroutine from the recv goroutine queue). All goroutine in recv goroutine queue will unshift out one by one and return a val=0 value and sentBeforeClosed=false.
2) if the send goroutine queue of chan is not empty, all goroutine will be extracted in turn and a panic for closing a close chan will be generated. Data sent to chan before this close is still stored in the value buffer of chan.
1.4 chan operating rules 4
Once chan is turned off, chan recv operations will never block, and data written before close in chan's value buffer still exists. Once all the data previously written by close in the value buffer has been fetched, subsequent receive operations will return val=0 and sentBeforeClosed=true.
Understanding the blocking and non-blocking operations of goroutine here is helpful to understand the select-case operations for chan. The select-case implementation mechanism is described below.
If there is no default branch in select-case, you must wait until a certain case branch meets the conditions and then wake up the corresponding goroutine to resume execution before you can continue execution, otherwise the code will be blocked here, that is, the current goroutine push will be transferred to the recv or send goroutine queue of the corresponding ch of each case branch, and the current goroutine may also be push to the recv and send goroutine queue queues for the same chan.
Whether it is a normal chan send or recv operation, or a select chan send or recv operation, because the goroutine blocked by the chan operation is awakened by the send and recv operations of other goroutine to chan. We have already talked about the timing of the awakening of goroutine, and we need to break it down here.
What is stored in the send and recv goroutine queue of chan is actually a structure pointer * sudog. The member gp * g points to the corresponding goroutine,elem unsafe.Pointer and points to the address of the variable to be read and written. C * hchan points to which chan on which goroutine is blocked. IsSelect indicates select chan send and recv, and vice versa means chan send and recv. G.selectDone indicates whether the select operation has been processed, that is, whether a case branch has been set up.
2.1 goroutine wake-up logic blocked by chan operations
Let's first describe the processing logic when a goroutine on chan is awakened. If a goroutine is blocked on the ch2 or ch3 because of the select chan operation, the corresponding sudog object will be created and the corresponding pointer * sudog push will be sent to the corresponding ch2, send and recv goroutine queue on each case branch, and it will be awakened while waiting for other co-programs to perform (select) chan send and recv operations: 1) Source file chan.go If another goroutine operates on ch2 now, and then performs a unshift operation on the goroutine of ch2 to fetch a blocked goroutine, execute the method * * func (Q * waitq) dequeue () sudog when unshift, which returns a blocked goroutine from the waiting queue of ch2.
Func (Q * waitq) dequeue () * sudog {for {sgp: = q.first if sgp = = nil {return nil} y: = sgp.next if y = = nil {q.first = nil Q.last = nil} else {y.prev = nil q.first = y sgp.next = nil / / mark as removed (see dequeueSudog)} / / if a goroutine was put on this queue because of a / / select There is a small window between the goroutine / / being woken up by a different case and it grabbing the / / channel locks. Once it has the lock / / it removes itself from the queue, so we won't see it after that. / / We use a flag in the G struct to tell us when someone / / else has won the race to signal this goroutine but the goroutine / / hasn't removed itself from the queue yet. If sgp.isSelect {if! atomic.Cas (& sgp.g.selectDone, 0,1) {continue}} return sgp}}
If the first element of the queue is the previously blocked goroutine, if its sgp.isSelect=true is detected, you will know that this is a goroutine blocked by select chan send and recv, and then set sgp.g.selectDone to true through the CAS operation to indicate that the select operation of the current goroutine has been processed, and then the goroutine can be returned to read from the value buffer or write data to value buffer, or exchange data directly with the goroutine that wakes it up. Then the blocked goroutine can resume execution.
Setting sgp.g.selectDone to true here means that the sgp.g has been withdrawn from the select-case block that just blocked it, and the corresponding select-case block can be invalidated. It is necessary to mention why the sgp.g.selectDone here is set to true. Wouldn't it be all right to put the goroutine out of the team? no way! Considering the following operation on chan, dequeue requires getting the lock on chan first, but it is possible that multiple chan branches of case are ready at the same time before attempting lock chan. Take a look at the sample code:
G1go func () {ch2
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.