C# - 将数据从ThreadPool线程传递回主线程

时间:2010-11-19 17:33:21

标签: c# multithreading .net-3.5 queue threadpool

当前实现:等待收集parallelCount值,使用ThreadPool处理值,等待所有线程完成,重新收集另一组值等等...

代码:

private static int parallelCount = 5;
private int taskIndex;
private object[] paramObjects;

// Each ThreadPool thread should access only one item of the array, 
// release object when done, to be used by another thread
private object[] reusableObjects = new object[parallelCount];     

private void MultiThreadedGenerate(object paramObject)
{
    paramObjects[taskIndex] = paramObject;
    taskIndex++;

    if (taskIndex == parallelCount)
    { 
        MultiThreadedGenerate();

        // Reset
        taskIndex = 0;
    }
}

/*
 * Called when 'paramObjects' array gets filled
 */
private void MultiThreadedGenerate()
{
    int remainingToGenerate = paramObjects.Count;

    resetEvent.Reset();

    for (int i = 0; i < paramObjects.Count; i++)
    {
        ThreadPool.QueueUserWorkItem(delegate(object obj)
        {
            try
            {
                int currentIndex = (int) obj;       

                Generate(currentIndex, paramObjects[currentIndex], reusableObjects[currentIndex]);
            }
            finally
            {
                if (Interlocked.Decrement(ref remainingToGenerate) == 0)
                {
                    resetEvent.Set();
                }
            }
        }, i);
    }

    resetEvent.WaitOne();    
}

我已经看到使用这种方法可以显着改善性能,但是需要考虑许多问题:

[1]可以避免在paramObjects中收集值并使用resetEvent进行同步,因为线程之间没有依赖关系(或者当前值集与下一组值之间)。我只是这样做来管理对reusableObjects的访问(当一个集paramObjects完成处理时,我知道reusableObjects中的所有对象都是空闲的,所以taskIndex被重置并且每个新任务下一组值将使用其独特的“reusableObj”。

[2] reusableObjects的大小与ThreadPool使用的线程数之间没有真正的联系。我可能会初始化reusableObjects以拥有10个对象,并说由于某些限制,ThreadPool只能为我的MultiThreadedGenerate()方法运行3个线程,然后我就是在浪费内存。

因此,通过删除paramObjects,如何以一种线程完成其作业的方式改进上述代码,该线程返回其taskIndex(或reusableObj })它已经使用,不再需要,以便它可用于下一个值。此外,代码应创建reUsableObject并仅在需要时将其添加到某个集合中。在这里使用Queue是一个好主意吗?

谢谢。

1 个答案:

答案 0 :(得分:5)

没有理由再进行自己的手动线程和任务管理了。您可以使用Task Parallel Library(以及可能System.Collections.Concurrent进行结果整理)将其重构为更松散耦合的模型。

如果您在递交每个Task进行处理之前无需等待完整的工作,则可以进一步提高性能。

TPL在.Net 4.0中出现但是back-ported to .Net 3.5。下载here