因此,我不熟悉通道,等待组,互斥锁等,并试图创建一个应用程序,该应用程序查询结构的一部分以获取数据,如果找到数据,则将其加载到映射中。我基本上是在尝试复制缓存/数据库方案(但是为了便于理解,目前在内存中都有这两种方案。)>
现在,在查询数据时,它既可以从数据库又可以从缓存中查询,我为此设置了一个RWMutex;但是在使用另一个go例程(通过通道)读取存储到缓存或db中的数据时。它从(db go-routine)和(cache go-routine)读取。所以我所做的就是每当我从高速缓存go例程中读取数据时,就耗尽了一个元素的db go路由。
package main import ( "fmt" "math/rand" "strconv" "sync" "time" ) type Book struct { id int name string } var cache = map[int]Book{} var books []Book var rnd = rand.New(rand.NewSource(time.Now().UnixNano())) func main() { cacheCh := make(chan Book) dbCh := make(chan Book) wg := &sync.WaitGroup{} m := &sync.RWMutex{} loadDb() for i := 0; i < 10; i++ { id := rnd.Intn(10) wg.Add(1) go func(id int, wg *sync.WaitGroup, m *sync.RWMutex, ch chan<- Book) { if find, book := queryCache(id, m); find { fmt.Println("Found Book In Cache: ", book) ch <- book } wg.Done() }(id, wg, m, cacheCh) wg.Add(1) go func(id int, wg *sync.WaitGroup, m *sync.RWMutex, ch chan<- Book) { if find, book := queryDb(id, m); find { ch <- book } wg.Done() }(id, wg, m, dbCh) go func(dbCh, cacheCh <-chan Book) { var book Book select { case book = <-cacheCh: msg := <-dbCh fmt.Println("Drain DbCh From: ", msg, "\nBook From Cache: ", book.name) case book = <-dbCh: fmt.Println("Book From Database: ", book.name) } }(dbCh, cacheCh) } wg.Wait() } func queryCache(id int, m *sync.RWMutex) (bool, Book) { m.RLock() b, ok := cache[id] m.RUnlock() return ok, b } func queryDb(id int, m *sync.RWMutex) (bool, Book) { for _, val := range books { if val.id == id { m.Lock() cache[id] = val m.Unlock() return true, val } } var bnf Book return false, bnf } func loadDb() { var book Book for i := 0; i < 10; i++ { book.id = i book.name = "a" + strconv.Itoa(i) books = append(books, book) } }
另外,我知道在这段代码中,即使它在缓存中找到不理想的命中,它也会始终查询数据库。但是,这只是一个测试场景,我优先考虑的是用户以尽可能最快的方式接收详细信息(即,如果缓存中不存在详细信息,则不应等待缓存的响应)在查询数据库之前)。
如果可能,请提供帮助,我对此还很陌生,所以可能有些琐碎。
对不起,谢谢。
因此,我不熟悉通道,等待组,互斥锁等,并试图创建一个应用程序,该应用程序查询结构的一部分以获取数据,如果找到数据,则将其加载到映射中。我基本上是想...
我看到的问题主要与对事物执行顺序的假设有关: