using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
public static ConcurrentDictionary<int, byte> PROCESSED = new ConcurrentDictionary<int, byte>();
static void Main(string[] args)
var services = new ServiceCollection();
services.AddMemoryCache();
services.AddTransient<JobServiceAsync>();
services.AddTransient<MyCacheServiceAsync>();
services.AddTransient<WorkerAsync>();
var serviceProvider = services.BuildServiceProvider();
var workers = Enumerable.Range(1, 100)
var w = serviceProvider.GetService<WorkerAsync>();
w.Skills = new int[] {1, 2};
var masterWorkers = Enumerable.Range(101, 100)
var w = serviceProvider.GetService<WorkerAsync>();
w.Skills = new int[] {4, 5};
workers.AddRange(masterWorkers);
var start = DateTime.Now;
var tasks = workers.Select(s => Task.Run(s.DoWorkAsync)).ToArray();
Console.WriteLine("Total Time {0}", end.Subtract(start));
Console.WriteLine("Total Processed {0}", PROCESSED.Count);
Console.WriteLine("Press any key");
public class MyCacheServiceAsync
private readonly IMemoryCache _memoryCache = null;
static SemaphoreSlim myLock = new SemaphoreSlim(1);
public MyCacheServiceAsync(IMemoryCache memoryCache)
_memoryCache = memoryCache ?? throw new ArgumentNullException(nameof(memoryCache));
public async Task<Job> FindAsync(int key, string title, int[] skills, Func<int, Task<List<Job>>> getJobs)
await myLock.WaitAsync();
List<Job> cachedJobs = null;
if (!_memoryCache.TryGetValue(key, out cachedJobs))
var jobs = await getJobs(key);
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromMinutes(30));
cachedJobs = _memoryCache.Set(key, jobs, cacheEntryOptions);
var job = cachedJobs.Where(j => j.Title == title &&
!j.Skills.Except(skills).Any())
private readonly MyCacheServiceAsync _cacheService;
private readonly JobServiceAsync _jobService;
public WorkerAsync(MyCacheServiceAsync cacheService, JobServiceAsync jobService)
_cacheService = cacheService;
_jobService = jobService;
public async Task DoWorkAsync()
var start = DateTime.Now;
var job = await _cacheService.FindAsync(WorkItemID, Title, Skills, _jobService.GetJobs);
Program.PROCESSED.TryAdd<int, byte>(job.JobID, 1);
Console.WriteLine("Job ID: {0}, WorkerID: {1}, Title:{2}, Time:{3}", job.JobID, WorkerID, Title, end.Subtract(start));
public class JobServiceAsync
public async Task<List<Job>> GetJobs(int workItemID)
await Task.FromResult(0);
List<Job> jobs = new List<Job>();
for (int i = 0; i < 5000; i++)
Skills = new int[] {1, 2}
for (int i = 0; i < 5000; i++)
public int JobID { get; set; }
public string Title { get; set; }
public int[] Skills { get; set; }