C# 线程池应用程序性能会随着时间的推移而下降

本文关键字:时间 线程 应用程序 性能 | 更新日期: 2023-09-27 18:33:36

我有一个类,比如"MyComputing",它在一个长构造函数中执行大量计算。自行执行时通常需要大约 20 毫秒才能运行(无需磁盘 I/O 或网络操作(。此类的 100 个左右实例由父类创建,例如"ComputeParent",它将它们作为工作项在 ThreadPool 中排队:

ThreadPool.QueueUserWorkItem(myComputationCall, my_computation_data);

"myComputingCall"看起来像这样:

    public static void myComputationCall(Object my_computation_data)
    {
        try
        {
            MyDataObject data = (MyDataObject)my_computation_data;
            var computation_run = new MyComputation(data.parameter1, data.parameter2);
            data.result = computation_run.result;
        }
        finally
        {
            if (Interlocked.Decrement(ref num_work_items_remaining) == 0)
                done_event.Set();
        }
    }

done_event是一个静态的手动重置事件:

    private static ManualResetEvent done_event;
    ...
    done_event = new ManualResetEvent(false);

对于各种输入参数,我运行ComputeParent大约500次左右。所以我有很多嵌套类。问题是执行ComputeParent所需的时间逐渐增加。运行每个特定 ComputeParent 所需的时间之间会有一定的差异,但时间量会非常稳定地增加(几何上,每次连续迭代花费的时间更长(。

程序的内存消耗不会随着时间的推移而显着增加,尽管它相当高(~300MB(。它在具有 8 个逻辑内核的计算机上运行,处理器使用似乎非常突发。我不确定还有什么可能与该问题相关。

我宁愿不必通过批处理文件运行 ComputeParent,尽管这样做时似乎不会出现问题。

C# 线程池应用程序性能会随着时间的推移而下降

如果 ThreadPool 中的可用线程数变为 0,并且您继续添加新的工作项,则新添加的工作项将"等待"。这意味着您的 ComputeParent 将等待其"myComputeCall"实例。启动越来越多的 ComputeParent 将导致它们的平均执行时间增加。

这个问题已经得到了回答。感谢所有的海报。

对于其他有类似问题的其他人,我会建议按照Henk的建议使用任务并行库。