2

I'm looking at using a ConcurrentDictionary to hold some cached data, which comes from a slow source (eg. a database).

The call to the database is async. So, is it possible to have the concurrent dictionary call an async method if the item doesn't exist in the dictionary?

for example:

const int userId = 1;
var cachedUsers = new ConcurrentDictionary<int, Task<User>>();
var user = await cachedUsers.GetOrAdd(userId, val => GetSlowDbResultAsync(userId, cancellationToken));

so what that pseduo code above is trying to do is say:

  • does User #1 exist in the C-Dict?
  • Yes, ok, use that.
  • No, grab user #1 from Db and stick it in the cache.

So - by putting the Task<User> into the concurrent-dictionary's 'value' (for a key/value):

  • is that ok?
  • does the code I wrote above, an acceptable use of this or have I just abused everything that is sacred with async/await/c#

Notes:

This question is inspired from my question on twitter.
This is similar to a previous question I asked but didn't get much traction.

Pure.Krome
  • 84,693
  • 113
  • 396
  • 647
  • If you wrap this up in a GetAsync method (so that the clients need not understand the implementation), you should be fine, I think. On the first hit, you'll await the database call, and on the second (for the same user id), you'll await the completed task. It seems fine to me. – ProgrammingLlama Oct 31 '17 at 02:24
  • 1
    Why did you choose `ConcurrentDictionary`? I hope you are not using async hoping it will speed things up. – CodingYoshi Oct 31 '17 at 02:41
  • See marked duplicate. Its answer uses exactly the technique you're asking about. It works fine, assuming the rest of your code is written to accommodate it. – Peter Duniho Oct 31 '17 at 02:58

1 Answers1

-4

How about try to write an extension method, something like:

class Extension
{
    public static User Get(this ConcurrentDictionary<int, User> conDict, int userID)
    {
        User user = null;
        if (!conDict.TryGetValue(userID, out user))
        {
            user = GetSlowDbResultAsync(userId, cancellationToken)
           conDict.TryAdd(userID, user);
        }

        return user;
    }
}

more information about extension method, please check with this article.

Sean
  • 1,806
  • 1
  • 13
  • 15