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

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

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.

func Get(key string){
    ...
    if itIsTheTimeToRefreshData{
         var once sync.Once
         onceBody := func() {
	    	fetchDataInBackground()
    	 }
		 go func() {
			once.Do(onceBody)
		 }()
     }
     ...
 }

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"),使用互斥访问的映射是可能的解决方案之一。

完整的工作示例:

package main

import (
	"fmt"
	"sync"
	"time"
)

var once map[string]bool
var onceMutex sync.Mutex
var itIsTheTimeToRefreshData = true

func Get(key string) {
	fmt.Printf("访问键:%s\n", key)
	if itIsTheTimeToRefreshData {
		onceBody := func() {
			fmt.Printf("只有一次的键:%s\n", key)
			// 在后台获取数据
		}

		onceMutex.Lock()
		if !once[key] { // 第一次访问?
			once[key] = true
			onceMutex.Unlock()

			// 在这里刷新一些内容
			go onceBody()
		} else {
			onceMutex.Unlock()
		}
	}
}

func main() {
	once = make(map[string]bool)

	// 并行地第一次访问
	for i := 0; i < 10; i++ {
		key := fmt.Sprintf("i%d", i)
		go func(key string) {
			Get(key)
		}(key)
	}
	// 第二次访问
	for i := 0; i < 10; i++ {
		key := fmt.Sprintf("i%d", i)
		go func(key string) {
			Get(key)
		}(key)
	}
	fmt.Println("所有请求已完成。")
	time.Sleep(1 * time.Second)
}

希望对你有帮助!

英文:

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:

package main

import (
        &quot;fmt&quot;
        &quot;sync&quot;
        &quot;time&quot;
)

var once map[string]bool
var onceMutex sync.Mutex
var itIsTheTimeToRefreshData = true

func Get(key string) {
        fmt.Printf(&quot;Access for key: %s\n&quot;, key)
        if itIsTheTimeToRefreshData {
                onceBody := func() {
                        fmt.Printf(&quot;Only once for key: %s\n&quot;, key)
                        //fetchDataInBackground()
                }

                onceMutex.Lock()
                if !once[key] { // is it first time?
                        once[key] = true
                        onceMutex.Unlock()

                        // refresh something here
                        go onceBody()
                } else {
                        onceMutex.Unlock()
                }
        }
}

func main() {
        once = make(map[string]bool)

        // do it first time in parallel
        for i := 0; i &lt; 10; i++ {
                key := fmt.Sprintf(&quot;i%d&quot;, i)
                go func(key string) {
                        Get(key)
                }(key)
        }
        // and another time
        for i := 0; i &lt; 10; i++ {
                key := fmt.Sprintf(&quot;i%d&quot;, i)
                go func(key string) {
                        Get(key)
                }(key)
        }
        fmt.Println(&quot;All requested.&quot;)
        time.Sleep(1 * time.Second)
}

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:

确定