我的线程池有什么问题?

时间:2012-03-30 18:35:42

标签: c# multithreading

我每天都有报道我试图从远程网络服务中集体收集我的代码如下:

    public static void ProcessEnMasse(System.DateTime fromDate, DateTime endDate)
    {
        System.Threading.ThreadPool.SetMaxThreads(10, 10);
        for (System.DateTime d = fromDate; d <= endDate; d = d.AddDays(1))
        {
            System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(day => ProcessOneDay(d)));
        }
    }

    public static void ProcessOneDay(System.DateTime theDate)
    {
        Log.Debug(string.Format("Processing {0:yyyy-MM-dd}...", theDate));
        var thePackager = new DataPackager();
        thePackager.CreateDatabaseImportPackage(theDate, theDate, true, false);
    }

...当我查看日志时,我注意到有几个线程正在处理相同的日期。为什么会这样,我需要做些什么才能防止这种情况发生?

3 个答案:

答案 0 :(得分:3)

你需要注意闭包(我会尽快给出更全面的解释)

基本上,您的代码应为:

public static void ProcessEnMasse(System.DateTime fromDate, DateTime endDate)
    {
        System.Threading.ThreadPool.SetMaxThreads(10, 10);
        for (System.DateTime d = fromDate; d <= endDate; d = d.AddDays(1))
        {
            System.DateTime newD = d;
            System.Threading.ThreadPool.QueueUserWorkItem
                (new System.Threading.WaitCallback(day => ProcessOneDay(newD)));
        }
    }

Here is Jon Skeet's chapter on closures

高级别的想法是(在原始代码中)传入d时,它实际上捕获了该变量,编译后的代码将使该变量充当全局共享变量。所以,当您点击下一个for步骤时,d不仅会更新您的循环,而且会更新您刚刚传入的函数。

这是高级别的,但我真的主张阅读Jon Skeet的文章,因为它写得非常好。

Here is another article如果您正在寻找更多:)

答案 1 :(得分:2)

所有lambda表达式共享相同的d变量。

如果其中一个工作项仅在初始线程运行d = d.AddDays(1)后启动,则它将使用该日期。

要解决此问题,请在循环体内声明一个单独的局部变量,然后使用它。

答案 2 :(得分:2)

你是“capturing the loop variable”。

要解决它:

for (System.DateTime d = fromDate; d <= endDate; d = d.AddDays(1))
{
     DateTime copy = d;
     System.Threading.ThreadPool.QueueUserWorkItem(
            new System.Threading.WaitCallback(day => ProcessOneDay(copy)));
}

或者您可以这样写(注意上面的代码中没有使用day):

for (System.DateTime d = fromDate; d <= endDate; d = d.AddDays(1))
{         
     ThreadPool.QueueUserWorkItem(day => ProcessOneDay((DateTime) day), d);
}