2
System.Threading.ThreadPool.SetMaxThreads(50, 50);
File.ReadLines().AsParallel().WithDegreeOfParallelism(100).ForAll((s)->{
/*
some code which is waiting external API call 
and do not utilize CPU 
*/
});

我的系统中的线程数从未超过 CPU 数。我可以使用 PLINQ 并让每个 CPU 获得多个线程吗?

4

5 回答 5

4

如果您正在调用外部 Web API,您可能会达到并发同时连接的限制,该限制设置为 2。在您的应用程序开始时,请执行以下操作:

System.Net.ServicePointManager.DefaultConnectionLimit = 4096;
System.Net.ServicePointManager.Expect100Continue = false;

试试看是否有帮助。如果没有,您尝试并行化的例程中可能存在其他瓶颈。

此外,正如其他响应者所说,ThreadPool 会根据负载决定启动多少线程。在我使用 TPL 的经验中,我发现线程数随着时间的推移而增加:应用程序运行时间越长,负载越重,启动的线程就越多。

于 2013-10-28T15:21:47.813 回答
1

我使用以下代码对此进行了测试:

var lines = Enumerable.Range(0, 200).ToArray();
int currentThreads = 0;
int maxThreads = 0;
object l = new object();
lines.AsParallel().WithDegreeOfParallelism(100).ForAll(
    s =>
    {
        lock (l)
        {
            currentThreads++;
            if (currentThreads > maxThreads)
            {
                maxThreads = currentThreads;
                Console.WriteLine(maxThreads);
            }
        }
        Thread.Sleep(3000);
        lock (l)
        {
            currentThreads--;
        }
    });

Console.WriteLine();
Console.WriteLine(maxThreads);

基本上,它记录当前并发执行的迭代次数,然后保存遇到的最大值。

结果变化很大,在 15 到 25 之间,但它总是比我的计算机的 CPU 数量 (4) 多得多。增加睡眠时间会增加最大并发线程数。所以看起来这里的限制因素是ThreadPool:它会缓慢地创建新线程,尤其是当作业完成相对较快时。

如果要增加使用的线程数,则需要使用SetMinThreads()(not SetMaxThreads())。如果我将最小值设置为 50,则实际使用的线程数约为 60。

但是拥有几十个只做等待的线程是非常低效的,尤其是在内存消耗方面。您应该考虑改用异步方法。

于 2013-10-28T16:36:10.663 回答
1

PLINQ 使用爬山算法来确定 TPL 使用的线程池的最佳大小。我认为如果你在你的任务中投入了大量的 I/O,那么看到比 CPU 数量更多的线程是很受欢迎的。

也就是说,我从未见过比 CPU 计数更多的线程 :) 。但也许我从来没有遇到过正确的情况。

于 2013-10-28T15:21:38.923 回答
0

PLINQ 不适合这种情况。我发现下一篇文章对我有用。 http://msdn.microsoft.com/en-us/library/hh228609(v=vs.110).aspx

于 2013-10-28T19:11:48.253 回答
-1

简短的回答:不。

线程的数量完全取决于 .Net Framework 运行时。没有开发人员可以控制 TPL(任务并行库)使用的线程数。

编辑

感谢其他一些反馈:实际上可以(但不推荐)手动控制 PLINQ 和 TPL 使用的 ThreadPool 中的线程数。

我认为任何并行化问题都需要仔细考虑,仔细构建和测试。这其中有很多微妙之处。

于 2013-10-28T15:16:44.507 回答