在C#中一次遍历X个线程的动作列表

Mat*_*att 2 .net c# multithreading

比方说我有一个

List<Thread> df = new List<Thread>();
// I add 500 instances of delegate() { somemethod(a,b) }; to df
Run Code Online (Sandbox Code Playgroud)

现在我想要运行所有df项目,一次最多线程化X项目,我该如何实现?

jri*_*sta 7

您可以使用多种选择.根据您可以访问的框架,选项可能会有所不同.通过.NET 4,您可以使用:Thread类w/Signals,ThreadPool,Asynchronous Delegate Invocation,Task Parallel Library.

我将在这里介绍您的几个选项,您可以选择最适合您需求的选项.

线程和信令

第一个选项是最手动的.您可以将Thread类的实例旋转到阈值X,并且每当线程完成时,都会启动另一个线程.

public void ProcessDelegates(IList<Action> thingsToDo, int maxConcurrency)
{
    int currentConcurrency = 0;
    var autoevent = new AutoResetEvent(false);
    foreach (var thingToDo in thingsToDo)
    {
        var thread = new Thread(
            () =>
            {
                thingToDo();
                autoevent.Set();
            }
        );

        if (++currentConcurrency >= maxConcurrency)
        {
            autoevent.WaitOne();
            --currentConcurrency;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

线程池

作为使用List的替代方法,您可以在ThreadPool中对工作项进行排队,并让它在闲暇时通过它们.警惕使用ThreadPool处理大量并发工作.每个AppDomain 有一个线程池,默认为大约25个并发线程.这些线程必须可用于处理该app域中的所有线程,包括运行时可能在后台执行的操作.ThreadPool只应用于少量并发工作项.

ThreadPool.QueueUserWorkItem(
    data =>
    {
        thingToDo(a, b);
    }
);
Run Code Online (Sandbox Code Playgroud)

异步委托调用

由于您使用的是委托,因此可以使用异步调用来实现线程.这是一种更抽象的多线程方法,有时更易于管理.在这种情况下,它与手动启动自己的线程非常相似.应该注意的是,Delegate.BeginInvoke在内部使用ThreadPool,并且适用于使用ThreadPool本身的相同规则也适用于此处.

public void ProcessDelegates(IList<Action> thingsToDo, int maxConcurrency)
{
    int currentConcurrency = 0;        
    IList<WaitHandle> resultHandles = new List<WaitHandle>();

    foreach (var thingToDo in thingsToDo)
    {
        var asyncResult = thingToDo.BeginInvoke();
        resultHandles.Add(asyncResult.AsyncWaitHandle);

        if (++currentConcurrency >= maxConcurrency)
        {
            WaitHandle.WaitAny(resultHandles.ToArray());
            --currentConcurrency;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

.NET 4任务并行库

如果您可以访问.NET 4,也可以尝试使用任务并行库.任务并行性是.NET 4中多线程的一种新方法,它提供了简单的使用和非常丰富的运行时调试功能.

在下面的示例中,TaskCreationOptions.PreferFairness告诉任务并行库尝试让先前启动的任务更早完成,从而导致通常顺序执行任务.

public void ProcessDelegates(IList<Action> thingsToDo)
{
    var tasks = thingsToDo.Select(
        ttd => Task.Factory.StartNew(ttd, TaskCreationOptions.PreferFairness)
    ).ToArray();

    Task.WaitAll(tasks);
}
Run Code Online (Sandbox Code Playgroud)

免责声明:这些例子不是我的头脑,而且显然过于简单,所以我不保证它们在真实场景中的完美稳定性.我建议使用这些作为基础来实现适用于您应用它们的任何应用程序的线程.