C#中多个线程之间的拆分操作

时间:2014-07-22 23:51:44

标签: c# multithreading

我正在编写基准应用程序,它具有线程数和要作为输入参数执行的操作数。 每个基准测试都创建为具有Execute(int numberOfRepeats)方法的独立类。 numberOfRepeats实际上是每个线程中的重复次数。

我通过以下方式创建基准:

例如,我有32个线程,以及50个持久的基准操作。因此每个线程必须执行 50/32 = 1操作(实际为1.56),这将为所有线程提供32个操作的总数。

我使用简单的"新的Thread()"构造多线程和AutoResetEvent与WaitHandle.WaitAll构造同步执行和测量总时间。

我尝试将 Parallel.For ParallelOptions.MaxDegreeOfParallelism 作为线程数,但它并没有实际运行所有线程的基准测试。由于操作数量 100k ,只有 20个线程在线程池中使用 ParallelOptions.MaxDegreeOfParallelism = 128

现在问题。如何在线程之间拆分操作以在我描述的情况下执行确切数量的操作?

谢谢!

3 个答案:

答案 0 :(得分:1)

并行调度程序不使用那么多线程,因为它足够聪明,知道何时这样做会降低性能。

来自MSDN

  

.NET线程池动态适应不断变化的工作负载   允许并行任务的工作线程数量发生变化   随着时间的推移。在运行时,系统观察是否增加   线程数会改善或降低整体吞吐量并进行调整   相应的工作线程数。

如果您使用这么多线程来执行基准,则应重新考虑您的实施。你会降低你的整体性能,因为线程会在每个周期中与每个周期进行斗争,这是你在尝试做基准时间敏感工作时最不想要的事情。

答案 1 :(得分:1)

我找到了在线程之间拆分任意数量操作的简便方法。 此方法将返回int的数组,其中每个元素表示具有索引i的线程的操作数。

    private static int[] splitTasksForThreads(int numberOfThreads, int numberOfTasks)
    {
        var tasksRepeatArray = new int[numberOfThreads];
        var taskPerThread = numberOfTasks / numberOfThreads;
        var diff = numberOfTasks - (numberOfThreads * taskPerThread);

        if (diff == 0)
        {
            for (int i = 0; i < numberOfThreads; i++)
                tasksRepeatArray[i] = taskPerThread;
        }
        else if (numberOfThreads > numberOfTasks)
        {
            for (int i = 0; i < numberOfTasks; i++)
            {
                tasksRepeatArray[i]++;
            }
        }
        else
        {
            for (int i = 0; i < tasksRepeatArray.Length; i++)
                tasksRepeatArray[i] = taskPerThread;
            for (int i = 0; i < diff; i++)
                tasksRepeatArray[i]++;
        }

        return tasksRepeatArray;
    }

答案 2 :(得分:0)

这是cmd函数的版本,如果操作超过包括注释的线程数,它将减少线程数量。我对此不承担任何责任。因为我的声誉不够高,所以无法发表评论。

internal static IEnumerable<int> GetActionsPerThreads(int numberOfThreads, int numberOfActions)
    {
        // We have too many threads for the requested amount of actions
        while (numberOfActions < numberOfThreads)
        {
            numberOfThreads--;
        }

        int[] actionsPerThread = new int[numberOfThreads];
        // Intentional loss of data
        int perThread = numberOfActions / numberOfThreads;
        int actionRemainder = numberOfActions - (numberOfThreads * perThread);

        // No need to split anything. The threads can perform an equal amount of actions
        if (actionRemainder == 0)
        {
            for (int i = 0; i < numberOfThreads; i++)
            {
                actionsPerThread[i] = perThread;
            }
        }
        // We have more actions than we have threads. Time to reduce our thread count to the amount of actions
        else if (numberOfThreads > numberOfActions)
        {
            for (int i = 0; i < numberOfActions; i++)
            {
                actionsPerThread[i]++;
            }
        }
        // We have an unequal amount of actions per thread, time to split them
        else
        {
            // All threads perform the calculated amount of actions (rounded down)
            for (int i = 0; i < actionsPerThread.Length; i++)
            {
                actionsPerThread[i] = perThread;
            }

            // Some tasks will have to do more work
            for (int i = 0; i < actionRemainder; i++)
            {
                actionsPerThread[i]++;
            }
        }
        return actionsPerThread;
    }