PLINQ内部任务有时会变慢

时间:2018-03-16 11:22:40

标签: c# parallel-processing

我正在研究一些文本解析器逻辑,并具有IO和CPU绑定操作。 一般来说我做的是:读取文件 - >处理文本,读取文件2 - >处理文本2 ...等等。

我能做的是让操作“进程文本”和“读取文件2”在不同的任务中同时执行。然而,当我创建相关任务树时,我注意到PLINQ变得比最初慢。以下是代码的简化示例:

课程计划 {     static int idx;

public static void Main()
{
    idx = 0;
    Stopwatch sw = new Stopwatch();
    sw.Start();

    for (int i = 0; i < 10; i++)
    {
        // here I execute my function with PLINQ
        FuncP();
    }

    sw.Stop();

    Console.WriteLine(sw.ElapsedMilliseconds);

    idx = 0;

    sw.Start();

    List<Task> tasks = new List<Task>();
    for (int i = 0; i < 10; i++)
    {
        int iLocal = i;
        Task tsk;
        if (i > 0)
        {
            // next task depends on previous one
            tsk = Task.Run(() =>
            {
                Task.WaitAll(tasks[iLocal - 1]);

                // execute the same function
                FuncP();
            });
        }
        else // i = 0
        {
            // first task does not depend on other tasks
            tsk = Task.Run(() =>
                {
                    // execute the same function
                    FuncP();
                });
        }

        tasks.Add(tsk);
    }

    tasks.Last().Wait();
    sw.Stop();

    Console.WriteLine(sw.ElapsedMilliseconds);
}

private static void FuncP()
{
    Stopwatch sw1 = new Stopwatch();
    sw1.Start();

    Console.WriteLine(string.Format("FuncP start {0}", ++idx));
    string s = new string('c', 2000);
    s.AsParallel()
        .ForAll(_ =>
        {
            for (int i = 0; i < 1000000; i++) ;
        });

    sw1.Stop();

    Console.WriteLine(string.Format("FuncP end {0}, Elapsed {1}", idx, sw1.ElapsedMilliseconds));
}

}

输出是:

FuncP start 1
FuncP end 1, Elapsed 409
FuncP start 2
FuncP end 2, Elapsed 345
FuncP start 3
FuncP end 3, Elapsed 344
FuncP start 4
FuncP end 4, Elapsed 337
FuncP start 5
FuncP end 5, Elapsed 344
FuncP start 6
FuncP end 6, Elapsed 343
FuncP start 7
FuncP end 7, Elapsed 348
FuncP start 8
FuncP end 8, Elapsed 351
FuncP start 9
FuncP end 9, Elapsed 343
FuncP start 10
FuncP end 10, Elapsed 334
3504
FuncP start 1
FuncP end 1, Elapsed 5522 --> here is high execution time
FuncP start 2
FuncP end 2, Elapsed 368
FuncP start 3
FuncP end 3, Elapsed 340
FuncP start 4
FuncP end 4, Elapsed 347
FuncP start 5
FuncP end 5, Elapsed 351
FuncP start 6
FuncP end 6, Elapsed 347
FuncP start 7
FuncP end 7, Elapsed 353
FuncP start 8
FuncP end 8, Elapsed 337
FuncP start 9
FuncP end 9, Elapsed 341
FuncP start 10
FuncP end 10, Elapsed 345
12160

有时它会在第一次运行PLINQ时挂起,有时会在第二次运行时挂起,但是对于任务,循环中需要花费更多时间。 我不确定我是否完全理解FuncP执行时间如此之高的原因,是不是AsParallel()由于线程池中缺少“空闲”线程而无法使其成为parellel? 谁能解释一下?提前谢谢。

1 个答案:

答案 0 :(得分:0)

这个问题很可能是因为线程池合理conservative (搜索文章中的Thread Injection它所包含的备用线程数。 Matt Warren的article值得一读。

如果您将ThreadPool设置为最小个线程数,例如使用:

ThreadPool.SetMinThreads(100, 100);

然后两个代码示例的行为大致相同,因为'备用'线程可用。

请注意,我不会建议在制作中使用100 - 这只是展示对比度的一个例子。