A while ago Scott Hanselman posted an article where they compare various methods of asynchronous synchronisation. Scott and Stephen Toub came up with a little class called AsyncLock that utilises SemaphoreSlim and IDisposable to make a nice little utility to block more than one thread from accessing a piece of code at a time. In Xamling-Core we extended this so you can have named locks (like a file name for example).
Recently we extended it a little further to allow you to throttle calls, so same idea as the full lock, but you can let through a few at a time.
For example, when resizing lots of images you could wrap your code in one of these ThrottleLocks and only four calls would run at a time.
TaskThrottler _getBlock = TaskThrottler.Get("ImageServiceProcess", 4); using (var l = await _getBlock.LockAsync()) { var result = await _imageResizeService.ResizeImage(fn, variantFile, size); ... }
Super simple.
Another adaption is allowing you to call the throttler directly to line up a bunch of processing then wait for the result.
There are two versions here – calling processes that return data and those that don’t.
With data returned:
List<Task<SomeEntity>> tasks = new List<Task<SomeEntity>>(); for (var i = 0; i < 500; i++) { var t = TaskThrottler.Get("Test", 50).Throttle(_getAnEntity); tasks.Add(t); Debug.WriteLine("Added: {0}", i); } await Task.WhenAll(tasks); ... async Task<SomeEntity> _getAnEntity() { var t = new SomeEntity() { Count = ++count }; await Task.Delay(1000); Debug.WriteLine("Actual: {0}", t.Count); return t; }
You can of course call methods that don’t have any return value.
So there you have it, a simple light weight asynchronous throttling utility.
Jordan.