Testing a list of proxies for validity concurrently I have a class that tests a list of proxies for validity concurrently, which I have created in 2 different ways, one utilizing Parallel.ForEach and the other using a TPL Dataflow ActionBlock.

I am just wondering which is one is preferred, and if I am overlooking something important.  As a side note, I created the Dataflow version because I want to be able to queue proxy tests, with the Parallel.ForEach version I could probably achieve that but it would take more code and some refactoring.

I still need some add some functionality to these methods. I realize the 'tests' parameter isn't being used.

Parallel.ForEach version:

public class ProxyTester
{
    public async Task ValidateProxiesAsync(IEnumerable&lt;Proxy&gt; proxies, IEnumerable&lt;ProxyJudge&gt; judges, IEnumerable&lt;ProxyTest&gt; tests)
    {
        await Task.Run(async () =&gt;
        {
            foreach (var proxy in proxies)
            {
                proxy.Status = ProxyStatus.Queued;
            }
            await proxies.ProcessWithParallelAsync(new Action&lt;Proxy&gt;((proxy =&gt;
            {
                proxy.Status = ProxyStatus.Testing;
                proxy.Status = proxy.TestValidity(judges.ElementAt(0));
            })));
        });
    }
}


ProcessWithParallelAsync Extension method:

public static async Task ProcessWithParallelAsync&lt;T&gt;(this IEnumerable&lt;T&gt; list, Action&lt;T&gt; action, int maxConcurrency = 100)
{
    await Task.Run(() =&gt; {
        var options = new ParallelOptions();
        options.MaxDegreeOfParallelism = maxConcurrency;
        Parallel.ForEach(list, options, action);
    });
}


TPL Dataflow version (supports queuing):

class ProxyTester2
{

    private ActionBlock&lt;(Proxy, IProxyTest)&gt; actionBlock;

    public ProxyTester2()
    {
        actionBlock = new ActionBlock&lt;(Proxy proxy, IProxyTest test)&gt;(tup =&gt;
        {
            tup.proxy.Status = ProxyStatus.Testing;
            tup.proxy.Status = tup.proxy.TestValidity(tup.test);
        }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 100 });
    }

    public void QueueProxyTest(Proxy proxy, IProxyTest test)
    {
        proxy.Status = ProxyStatus.Queued;
        actionBlock.Post((proxy, test));
    }

    public void QueueProxyTests(IEnumerable&lt;Proxy&gt; proxies, IEnumerable&lt;ProxyJudge&gt; judges, IEnumerable&lt;ProxyTest&gt; tests)
    {
        foreach (var proxy in proxies)
        {
            QueueProxyTest(proxy, judges.ElementAt(0));
        }
    }
}
You are starting two Task in ValidateProxiesAsync - one in the method and another in the extension method.  Really seems it should be one Task.  

Also judges is an IEnumerable that you are constantly doing ElementAt.  Should either do First and store that value for each call or pass in an IList or Array is that's what it really is if you need to access it by element 

As for Parallel.ForEach vs TPL DataFlow I think that depends on if you are building a data flow mesh (TPL DataFlow) or just want to process items in Parallel only (Parallel.ForEach)