Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

puzzled about func ConcurrentMap.Key() #91

Open
bluesky1024 opened this issue Nov 20, 2020 · 7 comments
Open

puzzled about func ConcurrentMap.Key() #91

bluesky1024 opened this issue Nov 20, 2020 · 7 comments

Comments

@bluesky1024
Copy link

func (m ConcurrentMap) Keys() []string {
	count := m.Count()

	time.Sleep(5*time.Second)

	ch := make(chan string, count)
	go func() {
		// Foreach shard.
		wg := sync.WaitGroup{}
		wg.Add(SHARD_COUNT)
		for _, shard := range m {
			go func(shard *ConcurrentMapShared) {
				// Foreach key, value pair.
				shard.RLock()
				for key := range shard.items {
					ch <- key
				}
				shard.RUnlock()
				wg.Done()
			}(shard)
		}
		wg.Wait()
		close(ch)
	}()

	// Generate keys
	keys := make([]string, 0, count)
	for k := range ch {
		keys = append(keys, k)
	}
	return keys
}

as the func shows, m.Count() is called before loop keys from shards.
However, there was no direct connect between Cont() res and the length of keys.
So why the func is designed to count first ?

@orcaman
Copy link
Owner

orcaman commented Nov 22, 2020

Count returns the number of items in the map (see this. It sums up the number of items in all shards (so going all shards and counting the number of elements on each).

@orcaman orcaman closed this as completed Nov 22, 2020
@bluesky1024
Copy link
Author

bluesky1024 commented Nov 23, 2020

@orcaman
the realize of Count() is clear, but the result of count may have changed when the keys loop. that's the point i do not understand. Is the operation of count with much shard lock necessary ?
what's more, the result of count() is unreliable for not locking all the shard at the same time. is there any plan to optimize this function?

@orcaman
Copy link
Owner

orcaman commented Nov 25, 2020

@bluesky1024 oh, I see what you mean now. So I would say that there are two approaches to getting keys from maps that I'm familiar with. The first approach is the redis approach - the infamous "keys" command, which locks the entire DB (or map in our case) until the count is done / keys are returned. And then there's a dynamic approach which is a bit more reliable than not locking at all but not 100% bullet-proof (like what we went for here).

I think it's not a bad idea to add a function more similar to redis, something like "KeysWithLock" (to make sure the user understands the performance consequences of using this). If you feel like it, it would be cool if you could create this and send a PR for review.

Anyway - reopening this for now.

@orcaman orcaman reopened this Nov 25, 2020
@bluesky1024
Copy link
Author

sorry for not notice your replay...
I'm not free these days with much work. And I will try to finish "KeysWithLock" in the future.

@lvxiaorun
Copy link

I also noticed this problem when I first came into contact with Cmap. I think the original intention of Cmap design is to sharde data and reduce the granularity of lock to increase the efficiency of read and write. We normally don't need to obtain all keys so rigor, so I think KeyswithLock is probably not important.

@baizhiwen
Copy link

Why use channel to receive data and then use the for loop to assign it to the string array? Why not just accept it as a string array?Higher performance or safer?

@yzbmz5913
Copy link

Why use channel to receive data and then use the for loop to assign it to the string array? Why not just accept it as a string array?Higher performance or safer?

Appending to a slice concurrently is not safe.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants