New answers tagged

9

If you modify the AsyncDictionary while enumerating its keys/values it throws InvalidOperationException (if the backing dictionary is a Dictionary). var numbers = new AsyncDictionary<int, int>(); foreach(var number in Enumerable.Range(1, 1000)) { await numbers.AddAsync(number, number); } foreach(var number in await numbers.GetKeysAsync()) { ...


11

It's pretty hard to break something that uses a global lock around everything. So this seems pretty thread-safe. But that doesn't answer the question of why you'd want to use this. Asynchronous calls are useful for things that take a long time, particularly if you can delegate the "waiting" to some low-level event based solution (HTTP requests for example)....


24

The reason why there is no async API for a dictionary is, that all operations on a dictionary are so fast, that there is no need for asynchronicity. For concurrent scenarios there is the thread safe variant - the ConcurrentDictionary. Adding an async API to these dictionaries has absolutely zero value. Rather it increases complexity and reduces performance....


11

Threading Design Your implementation has a very intrusive lock for all read and write operations, using the SemaphoreSlim with max concurrency 1. try { await _semaphoreSlim.WaitAsync()// <- both read/write operations acquire single mutex return await Task.Run(async () => { return await func(_dictionary, keyValuePair); }); } ...


2

Cancellation Token Source You create a token source, and then immediately overwrite it with a new instance, disregarding the previously created instance. Surely, you did not mean to instantiate it twice? _runningSubscriberCancellationTokenSource = new CancellationTokenSource(); _runningSubscriberCancellationTokenSource = CancellationTokenSource....


2

Generally, the code is simple and easy to understand. Concurrency It's good that you have a dedicated Lock object. You might consider a more expressive name, but in this case I think you can get away with it. As you have noticed, using the lock means you gain nothing from the ConcurrentDictionary'2. Since this is such a simple interface, I would keep the ...


6

You can simplify GetOrCreateAsync() a bit, because IMemoryCache has an extension called Microsoft.Extensions.Caching.Memory.GetOrCreateAsync(): public async Task<T> GetOrCreateAsync<T>(object key, Func<ICacheEntry, Task<T>> create) { await Locker.WaitAsync(); try { return await _cache.GetOrCreateAsync(key, create); } ...


7

Sorry this is a bit of a ramble, but a few things jump out at me: 17?!?! I don't have to tell you about magic numbers! This should probably be configurable... somehow... Why is Locker static? It doesn't make sense to restrict access to one cache because a totally different cache is currently in use. Locking the cache while you create an item isn't ...


Top 50 recent answers are included