Blocking object in asynchronous operation

I have the following code with which I want to achieve the following.

  • Check if the value is in cache
  • If in cache to receive value from it and continue
  • If not in the cache, follow the logic to enter it in the cache, but do it asynchronously, since the operation to be performed may take a long period of time, and I do not want to delay the user

As you will see in my code, I put the lock in the cache in an asynchronous stream. Is my setting below thread safe? And by placing a lock, this will mean that the cache will not be readable by other caches from the cache during the async operation. I do not want the case when the cache is blocked in an asynchronous stream, not allowing other requests to access it.

There is also the possibility that the same request may be caused by multiple threads, hence blocking.

Any recommendations on how I could improve the code would be great.

// Check if the value is in cache
        if (!this.Cache.Contains(key))
        {
            // Perform processing of files async in another thread so rendering is not slowed down
            ThreadPool.QueueUserWorkItem(delegate
            {
                lock (this.Cache)
                {
                    if (!this.Cache.Contains(key))
                    {
                        // Perform the operation to get value for cache here
                        var cacheValue = operation();

                        this.Cache.Add(key, cacheValue);
                    }
                }
            });

            return "local value";
        }
        else
        {
            // Return the string from cache as they are present there
            return this.Cache.GetFilename(key);
        }

Note. this.Cache represents a cache object.

The application is a .net 3.5 web application.

+3
source share
3 answers

How to change a delegate to look like this:

var cacheValue = operation();
lock (this.Cache)
            {
                if (!this.Cache.Contains(key))
                {
                    // Perform the operation to get value for cache here

                    this.Cache.Add(key, cacheValue);
                }
            }

This type of coding locks the dictionary for a very short time. You can also try using ConcurrentDictionary, which basically does not block at all.

Alex

+1
source

. : Cache.Contains lock, ; operation lock, ; .

, :

class Cache<TKey, TValue>
{
    private readonly ConcurrentDictionary<TKey, Task<TValue>> items;

    public Cache()
    {
        this.items = new ConcurrentDictionary<TKey, Task<TValue>>();
    }

    public Task<TValue> GetAsync(TKey key, Func<TKey, TValue> valueFactory)
    {
        return this.items.GetOrAdd(key,
            k => Task.Factory.StartNew<TValue>(() => valueFactory(k)));
    }
}

GetAsync : , items . , valueFactory ThreadPool Task, . GetAsync , , valueFactory. , , .

:

var cache = new Cache<string, int>();

Task<int> task = cache.GetAsync("Hello World", s => s.Length);

// ... do something else ...

task.Wait();
Console.WriteLine(task.Result);
+1

, . , , , , .

( , (). , lock().

" " ? ?

0

Source: https://habr.com/ru/post/1778866/


All Articles