I've got some methods that follow a similar pattern, and wanted to abstract some of the logic away into an extension method. Specifically, I am processing lists of objects with the TPL, and throttling that processing with a SemaphoreSlim
.
public static Task ValidateProxiesAsync(IList<Proxy> proxies, IList<ProxyJudge> judges, IList<ProxyTest> tests)
{
return Task.Run(async () =>
{
await ValidateTestsAsync(judges.ToList<IProxyTest>());
await ValidateTestsAsync(tests.ToList<IProxyTest>());
var semaphore = new SemaphoreSlim(100);
var tasks = new List<Task>();
foreach (var proxy in proxies)
{
await semaphore.WaitAsync();
tasks.Add(Task.Run(() =>
{
proxy.Status = proxy.TestValidity(judges[0]);
semaphore.Release();
}));
}
await Task.WhenAll(tasks);
});
}
public static Task ValidateTestsAsync(IList<IProxyTest> tests)
{
return Task.Run(async () =>
{
var semaphore = new SemaphoreSlim(100);
var tasks = new List<Task>();
foreach (var test in tests)
{
await semaphore.WaitAsync();
tasks.Add(Task.Run(() =>
{
test.Status = test.TestValidity();
semaphore.Release();
}));
}
await Task.WhenAll(tasks);
});
}
I wrote this extension method to reduce the LOC needed to do this. But I wanted to make sure I didn't overlook something. Perhaps there is a better solution that someone on here could suggest (TPL Dataflow?).
Extension method:
public static Task ProcessWithSemaphoreAsync<T>(this IList<T> list, Action<T> action, int maxConcurrency)
{
return Task.Run(async () => {
var semaphore = new SemaphoreSlim(maxConcurrency);
var tasks = new List<Task>();
foreach (var item in list)
{
await semaphore.WaitAsync();
tasks.Add(Task.Run(() =>
{
action.Invoke(item);
semaphore.Release();
}));
}
await Task.WhenAll(tasks);
});
}