// Exercise 1: a ValueTask cache that deduplicates concurrent loads (medium) // // UserCache.GetAsync(id) returns a ValueTask: // - On a cache hit it must complete SYNCHRONOUSLY (vt.IsCompletedSuccessfully == true) without allocating a Task. // - On a miss it calls the loader. If several callers ask for the same missing id concurrently, the loader // must run only ONCE: keep in-flight loads in a ConcurrentDictionary> and share them. // - When the load completes, store the value in _values so later calls are synchronous hits, and remove // the in-flight entry. // // Run with: dotnet run (inside a console project). using System; using System.Collections.Concurrent; using System.Threading.Tasks; class UserCache { readonly Func> _loader; readonly ConcurrentDictionary _values = new(); readonly ConcurrentDictionary> _inflight = new(); public UserCache(Func> loader) { _loader = loader; } public ValueTask GetAsync(int id) { // TODO return new ValueTask(_loader(id)); } } class Program { static async Task Main() { int pass = 0, total = 0; void Check(string name, bool ok) { total++; if (ok) pass++; Console.WriteLine($"{(ok ? "PASS" : "FAIL")}: {name}"); } int calls = 0; var cache = new UserCache(async id => { System.Threading.Interlocked.Increment(ref calls); await Task.Delay(100); return "user-" + id; }); var t1 = cache.GetAsync(7).AsTask(); var t2 = cache.GetAsync(7).AsTask(); var t3 = cache.GetAsync(7).AsTask(); var results = await Task.WhenAll(t1, t2, t3); Check("all callers get the value", results[0] == "user-7" && results[1] == "user-7" && results[2] == "user-7"); Check($"loader ran once for concurrent misses (ran {calls})", calls == 1); var hit = cache.GetAsync(7); Check("cache hit completes synchronously", hit.IsCompletedSuccessfully && hit.Result == "user-7"); Check("no extra load on hit", calls == 1); await cache.GetAsync(8); Check("different key loads separately", calls == 2); Console.WriteLine($"--- {pass}/{total} checks passed ---"); } }