How to run a golang function call once per key parameter in concurrent environment?

huangapple go评论111阅读模式
英文:

How to run a golang function call once per key parameter in concurrent environment?

问题

这个例子似乎只会获取一次数据,但我不认为它会同时为每个key在后台调用fetchDataInBackground函数。

我需要做的是将每个Once实例分配给一个key,以便可以同时获取不同key的所有数据。我该怎么做?

英文:

This example seems to fetch data once, but I don't think it will invoke a fetchDataInBackground function in background for each key concurrently.

  1. func Get(key string){
  2. ...
  3. if itIsTheTimeToRefreshData{
  4. var once sync.Once
  5. onceBody := func() {
  6. fetchDataInBackground()
  7. }
  8. go func() {
  9. once.Do(onceBody)
  10. }()
  11. }
  12. ...
  13. }

what I need to do is to assign each Once instance to a key so that all fetch data for different keys can be done concurrently.
how do I do that?

答案1

得分: 4

我认为sync.Once对于这样的任务不太适用。你需要为每个键维护一些标志("once"),使用互斥访问的映射是可能的解决方案之一。

完整的工作示例:

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. "time"
  6. )
  7. var once map[string]bool
  8. var onceMutex sync.Mutex
  9. var itIsTheTimeToRefreshData = true
  10. func Get(key string) {
  11. fmt.Printf("访问键:%s\n", key)
  12. if itIsTheTimeToRefreshData {
  13. onceBody := func() {
  14. fmt.Printf("只有一次的键:%s\n", key)
  15. // 在后台获取数据
  16. }
  17. onceMutex.Lock()
  18. if !once[key] { // 第一次访问?
  19. once[key] = true
  20. onceMutex.Unlock()
  21. // 在这里刷新一些内容
  22. go onceBody()
  23. } else {
  24. onceMutex.Unlock()
  25. }
  26. }
  27. }
  28. func main() {
  29. once = make(map[string]bool)
  30. // 并行地第一次访问
  31. for i := 0; i < 10; i++ {
  32. key := fmt.Sprintf("i%d", i)
  33. go func(key string) {
  34. Get(key)
  35. }(key)
  36. }
  37. // 第二次访问
  38. for i := 0; i < 10; i++ {
  39. key := fmt.Sprintf("i%d", i)
  40. go func(key string) {
  41. Get(key)
  42. }(key)
  43. }
  44. fmt.Println("所有请求已完成。")
  45. time.Sleep(1 * time.Second)
  46. }

希望对你有帮助!

英文:

I think sync.Once is not well for such task. You need to maintain some flag ("once") for each key individually. Map with mutexed access is one of possible solutions.

Full working example:

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;sync&quot;
  5. &quot;time&quot;
  6. )
  7. var once map[string]bool
  8. var onceMutex sync.Mutex
  9. var itIsTheTimeToRefreshData = true
  10. func Get(key string) {
  11. fmt.Printf(&quot;Access for key: %s\n&quot;, key)
  12. if itIsTheTimeToRefreshData {
  13. onceBody := func() {
  14. fmt.Printf(&quot;Only once for key: %s\n&quot;, key)
  15. //fetchDataInBackground()
  16. }
  17. onceMutex.Lock()
  18. if !once[key] { // is it first time?
  19. once[key] = true
  20. onceMutex.Unlock()
  21. // refresh something here
  22. go onceBody()
  23. } else {
  24. onceMutex.Unlock()
  25. }
  26. }
  27. }
  28. func main() {
  29. once = make(map[string]bool)
  30. // do it first time in parallel
  31. for i := 0; i &lt; 10; i++ {
  32. key := fmt.Sprintf(&quot;i%d&quot;, i)
  33. go func(key string) {
  34. Get(key)
  35. }(key)
  36. }
  37. // and another time
  38. for i := 0; i &lt; 10; i++ {
  39. key := fmt.Sprintf(&quot;i%d&quot;, i)
  40. go func(key string) {
  41. Get(key)
  42. }(key)
  43. }
  44. fmt.Println(&quot;All requested.&quot;)
  45. time.Sleep(1 * time.Second)
  46. }

huangapple
  • 本文由 发表于 2016年11月19日 23:38:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/40694698.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定