我国古代名医扁鹊本名叫甚么?蚂蚁庄园扁鹊本名叫甚么

知识 3℃

上面对是作古一个 select 作古锁的问题

package mainimport "sync"func main() {  var wg sync.WaitGroup foo := make(chan int) bar := make(chan int) wg.Add(1) go func() {   defer wg.Done()  select {   case foo <- <-bar:  default:   println("default")  } }() wg.Wait()}

按常例邃晓 ,go func 中的个细 select 理应奉行 default 分支,法度圭表类型正常运转。作古但下场却不是个细 ,而是作古作古锁 。可以经由过程该链接测试:https://play.studygolang.com/p/kF4pOjYXbXf 。个细

启事文章也诠释了,作古Go 言语圭表类型中有这么一句:

For all the cases in the statement,个细 the channel operands of receive operations and the channel and right-hand-side expressions of send statements are evaluated exactly once, in source order, upon entering the “select” statement. The result is a set of channels to receive from or send to, and the corresponding values to send. Any side effects in that evaluation will occur irrespective of which (if any) communication operation is selected to proceed. Expressions on the left-hand side of a RecvStmt with a short variable declaration or assignment are not yet evaluated.

不晓得大年夜师看懂没有 ?是以 ,最初来了一个例子验证你可否邃晓了 :为甚么每次都是作古输进一折半据,然后作古锁?个细(一样,这里可以运转搜检下场 :https://play.studygolang.com/p/zoJtTzI7K5T)

package mainimport ( "fmt" "time")func talk(msg string,作古 sleep int) <-chan string {  ch := make(chan string) go func() {   for i := 0; i < 5; i++ {    ch <- fmt.Sprintf("%s %d", msg, i)   time.Sleep(time.Duration(sleep) * time.Millisecond)  } }() return ch}func fanIn(input1, input2 <-chan string) <-chan string {  ch := make(chan string) go func() {   for {    select {    case ch <- <-input1:   case ch <- <-input2:   }  } }() return ch}func main() {  ch := fanIn(talk("A", 10), talk("B", 1000)) for i := 0; i < 10; i++ {   fmt.Printf("%q\n", <-ch) }}

有没有这类感应感染:

这是 StackOverflow 上的一个问题 :https://stackoverflow.com/questions/51167940/chained-channel-operations-in-a-single-select-case。

关头点和文章开首例子一样,个细在于 select case 中两个 channel 串起来 ,作古即 fanIn 函数中  :

select { case ch <- <-input1:case ch <- <-input2:}

假定改成多么就实足正常 :

select { case t := <-input1:  ch <- tcase t := <-input2:  ch <- t}

连络这个更宏壮的个细例子分化 Go 言语圭表类型中的那句话。

对 select 语句 ,作古在进进该语句时,会按源码的按序对每个 case 子句举办求值:这个求值只针对发送或领受独霸的出格表达式 。

比如:

// ch 是一个 chan int;// getVal() 前去 int// input 是 chan int// getch() 前去 chan intselect {   case ch <- getVal():  case ch <- <-input:  case getch() <- 1:  case <- getch():}

在没有选择某个具体 case 奉行前,例子中的 getVal() 、 <-input 和 getch() 会奉行 。这里有一个验证的例子 :https://play.studygolang.com/p/DkpCq3aQ1TE。

package mainimport ( "fmt")func main() {  ch := make(chan int) go func() {   select {   case ch <- getVal(1):   fmt.Println("in first case")  case ch <- getVal(2):   fmt.Println("in second case")  default:   fmt.Println("default")  } }() fmt.Println("The val:", <-ch)}func getVal(i int) int {  fmt.Println("getVal, i=", i) return i}

非论 select 幻想下场选择了哪个 case, getVal() 都邑屈就源码按序奉行 : getVal(1) 和 getVal(2) ,也就是它们必定先输进:

getVal, i= 1getVal, i= 2

你可以细心猜测一下。

如今回到 StackOverflow 上的阿谁问题 。

每次进进以下 select 语句时:

select { case ch <- <-input1:case ch <- <-input2:}

<-input1 和 <-input2 都邑奉行 ,照顾的值是:A x 和 B x(个中 x 是 0-5)。但每次 select 只会选择个中一个 case 奉行 ,所以 <-input1 和 <-input2 的下场,必定有一个被扔掉落踪了,也就是不会被写进 ch 中 。是以 ,一共只会输进 5 次,此外 5 次下场丢损掉落踪落了 。(你会创作创造 ,输进的 5 次下场中,x 比如是 0 1 2 3 4)

而 main 中轮回 10 次,只掉落踪掉落踪 5 次下场 ,所以输进 5 次后,报作古锁 。

当然这是一个小细节,但理论斥地中仍是有大年夜大年夜约展示的 。比如文章提到的例子写法 :

// ch 是一个 chan int;// getVal() 前去 int// input 是 chan int// getch() 前去 chan intselect {   case ch <- getVal():  case ch <- <-input:  case getch() <- 1:  case <- getch():}

是以在独霸 select 时,必定要寄看这类大年夜大年夜约的问题。

不要感应这个问题不会碰着,真实很罕有 。最多的就是 time.After 招致内存泄漏问题 ,网上有良多文章诠释启事 ,若何阻拦 ,真实最根柢启事就是因为 select 这个机制招致的。

比如以下代码,有内存泄漏(传递给 time.After 的时分参数越除夜,泄漏会越短长),你能诠释启事吗?

package mainimport (    "time")func main()  {     ch := make(chan int, 10)    go func() {         var i = 1        for {             i++            ch <- i        }    }()    for {         select {         case x := <- ch:            println(x)        case <- time.After(30 * time.Second):            println(time.Now().Unix())        }    }}

到此这篇关于Go select 作古锁的一个细节的文章就引见到这了,更多相干Go select 作古锁内容请搜刮完竣下载之前的文章或延续不雅不雅不雅不雅鉴赏上面的相干文章希看大年夜师往后多多支撑完竣下载!