Golang Go语言中的 select 方法很适合 cache 啊
在这里看到的。https://mzh.io/%E4%B8%80%E4%BA%9BGolang%E5%B0%8F%E6%8A%80%E5%B7%A7
在 nsq 中,需要读取之前磁盘上的,或者是从内存中直接读取,一般人都是先判断内存中有没有数据,然而,nsq 另辟蹊径使用了 select 语句,把 CSP 模式用到了极致。
select {
case msg = <-c.memoryMsgChan: //尝试从内存中读取
case buf = <-c.backend.ReadChan(): //如果内存中没有,直接从磁盘上读取
msg, err = decodeMessage(buf)
if err != nil {
c.ctx.nsqd.logf("ERROR: failed to decode message - %s", err)
continue
}
这个想法蛮好啊。
Golang Go语言中的 select 方法很适合 cache 啊
更多关于Golang Go语言中的 select 方法很适合 cache 啊的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
go 是最好的语言,go 实现的网站
www.cshome.com
更多关于Golang Go语言中的 select 方法很适合 cache 啊的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你需要多开 channel 和 goroutine,这是占一些资源的 不过可以忽略。go 语言级别支持 csp,go 的 select 是在用户态中进行对 goroutine 的调度。
但是从 channel 中取出后,channel 中的消息已经没有了,这样还需要在消费后再将消息推送进 channel,并且还要自己维护失效时间。
对的 这个是要自己再搞下。
go 并没有承诺 select 前面的高优先级,实测也发现并不是按照顺序确定优先级,而是乱序。<br><br>package main<br><br>import (<br> "fmt"<br> "time"<br>)<br><br>func main() {<br><br> c1 := make(chan int, 10)<br> c2 := make(chan int, 10)<br><br> go func() {<br> for i := 0; i < 100; i++ {<br> c1 <- 1<br> }<br> }()<br> go func() {<br> for i := 0; i < 100; i++ {<br> c2 <- 2<br> }<br> }()<br><br> time.Sleep(100 * time.Millisecond)<br><br> for {<br> select {<br> case i := <-c1:<br> fmt.Println(i)<br> case i := <-c2:<br> fmt.Println(i)<br> }<br> }<br><br>}<br><br>
输出结果:
1
2
2
2
1
2
1
1
2
1
2
2
2
1
2
1
2
2
2
2
1
1
2
1
2
1
2
1
2
1
2
2
2
2
1
1
1
2
1
2
2
1
1
2
1
1
2
2
2
1
1
2
2
2
1
2
1
2
1
2
2
2
1
慎用,case 后面的都会被执行,本质上是在比哪个 case 更快返回
func TestSelectCase(t *testing.T) {
var fromCache = func() chan int {
t.Log(“call fromCache()”)
c := make(chan int, 1)
<-time.After(time.Second * 1)
c <- 1
return c
}
var fromDB = func() chan int {
t.Log(“call fromDB()”)
c := make(chan int, 1)
<-time.After(time.Second * 2)
c <- 1
return c
}
select {
case <-fromCache():
t.Log(“got from cache”)
case <-fromDB():
t.Log(“got from db”)
}
}
select_case_test.go:11: call fromCache()
select_case_test.go:21: call fromDB()
select_case_test.go:34: got from db
/////////////////////////
func TestSelectCase(t *testing.T) {
var fromCache = func() chan int {
t.Log(“call fromCache()”)
c := make(chan int, 1)
go func() {
<-time.After(time.Second * 1)
c <- 1
}()
return c
}
var fromDB = func() chan int {
t.Log(“call fromDB()”)
c := make(chan int, 1)
go func() {
<-time.After(time.Second * 2)
c <- 1
}()
return c
}
select {
case <-fromCache():
t.Log(“got from cache”)
case <-fromDB():
t.Log(“got from db”)
}
}
select_case_test.go:11: call fromCache()
select_case_test.go:23: call fromDB()
select_case_test.go:36: got from cache
你给一个页面怎么看出来是 go 实现的
所以 select 还要考虑 switch 的条件,case 的条件同一时刻只满足一个,如果同时满足多个 调度器选择执行哪一个都是有可能的
所以我说感觉就是这个场景的(缓存)下,这种设计还是很精妙的。
学到了,golang 文档好像没有写明
有弊端。 当缓存和硬盘中都有数据的时候, 理论上是想从缓存读取,这样速度快,才起到缓存的作用,而却从硬盘取数据了,这样即使有缓存数据也没有起到作用。 所以 这种写法只适合非常简单的一种缓存机制,即使从硬盘取也不会很慢。 真要做大规模的缓存,不适合吧,当高并发的时候,会太多缓存失效的情况会发生,而实际中这些缓存数据都是有的
这样做的前提是读压力小,读压力大的话,磁盘 io 直接就爆了
这代码逻辑有问题啊,有可能在有缓存的时候读盘,吹 go 不是这么吹的
这里也有讲的。
唔~ 有道理~
这个是看哪个 case 运气好被执行了
这个域名不做 CSGO 社区可以了……
select 的一个神坑就是多个 case 之间是无序的,当都有数值的时候会随机的返回其中一个 case,巨恶心。
代码逻辑没问题,建议看完整的代码。你贴的代码里那段中文注释错了,这里不是 if else,是 or 的关系。select 本身是无序的。
说 select-case 无序是坑的,官方文档早就说明得很详细了,而且这特性可以实现一些比较有意思的功能。
敢问坑在哪里?
两个都是 channel,应该是谁刚好有数据就选谁。channel 不可能主动去查磁盘吧?应该要别的 goroutine 从磁盘查数据放进 channel。
在Go语言中,select
语句确实非常适合用于处理缓存(cache)相关的并发场景。select
语句可以监听多个通信操作(如发送和接收)并在其中一个操作可以立即进行时执行它,这使得它成为处理缓存读取和写入时的理想选择。
缓存通常需要在多个goroutine之间共享,以支持并发的读写操作。通过使用select
语句,我们可以优雅地处理以下几种情况:
-
缓存命中:当缓存中有数据时,我们可以立即从缓存中读取数据,而无需等待或阻塞。
-
缓存未命中:当缓存中没有数据时,我们可以使用
select
语句来监听从其他来源(如数据库或远程服务)获取数据的通道。一旦数据可用,select
语句将自动选择该通道并处理数据,然后将其存入缓存以供后续使用。 -
超时处理:在访问缓存时,我们可能希望设置一个超时时间,以避免长时间的等待。
select
语句可以很容易地实现这一点,通过监听一个带有超时的通道来触发超时处理逻辑。
总之,select
语句在Go语言中提供了一种强大且灵活的方式来处理并发通信,这使得它成为实现高效缓存系统的关键工具。通过合理地使用select
语句,我们可以构建出既能够高效处理并发读写操作,又能够优雅地处理各种异常情况(如缓存未命中和超时)的缓存系统。