为什么 PLINQ 只使用两个线程?

发布于 2024-08-12 16:42:51 字数 845 浏览 6 评论 0原文

假设我有一个 IO 密集型任务。我正在使用 WithDegreeOfParallelism = 10 和 WithExecution = ForceParallelism 模式,但查询仍然只使用两个线程。为什么?

我知道 PLINQ 通常会选择等于我的核心数的并行度,但为什么它会忽略我对更高并行度的具体要求?

static void Main(string[] args)
{
    TestParallel(0.UpTo(8));
}

private static void TestParallel(IEnumerable<int> input)
{
    var timer = new Stopwatch();
    timer.Start();
    var size = input.Count();

    if (input.AsParallel().
        WithDegreeOfParallelism(10).
        WithExecutionMode(ParallelExecutionMode.ForceParallelism).
        Where(IsOdd).Count() != size / 2)
        throw new Exception("Failed to count the odds");

    timer.Stop();
    Console.WriteLine("Tested " + size + " numbers in " + timer.Elapsed.TotalSeconds + " seconds");
}

private static bool IsOdd(int n)
{
    Thread.Sleep(1000);
    return n%2 == 1;
}

Say I have an IO-bound task. I'm using WithDegreeOfParallelism = 10 and WithExecution = ForceParallelism mode, but still the query only uses two threads. Why?

I understand PLINQ will usually choose a degree of parallelism equal to my core count, but why does it ignore my specific request for higher parallelism?

static void Main(string[] args)
{
    TestParallel(0.UpTo(8));
}

private static void TestParallel(IEnumerable<int> input)
{
    var timer = new Stopwatch();
    timer.Start();
    var size = input.Count();

    if (input.AsParallel().
        WithDegreeOfParallelism(10).
        WithExecutionMode(ParallelExecutionMode.ForceParallelism).
        Where(IsOdd).Count() != size / 2)
        throw new Exception("Failed to count the odds");

    timer.Stop();
    Console.WriteLine("Tested " + size + " numbers in " + timer.Elapsed.TotalSeconds + " seconds");
}

private static bool IsOdd(int n)
{
    Thread.Sleep(1000);
    return n%2 == 1;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

梦毁影碎の 2024-08-19 16:42:51

PLINQ 尝试找到最佳线程数来尽快执行您希望它执行的操作,如果您的 cpu 上只有 2 个核心,该数字很可能是 2。如果您有一个四核,您会更可能会看到 4 个线程出现,但在双核计算机上创建 4 个线程并不会真正提高性能,因为只有 2 个线程可以同时处于活动状态。

此外,对于基于 IO 的操作,任何额外的线程很可能会在执行的第一个 IO 操作上简单地阻塞。

PLINQ tries to find the optimal number of threads to perform what you want it to do as quickly as possible, if you only have 2 cores on your cpu, that number is most likely 2. If you had a quad core, you would be more likely to see 4 threads appear, but creating 4 threads on a dual core machine wouldn't really improve performance because only 2 threads could be active at the same time.

Also, with IO-based operations, it is likely that any extra threads would simply block on the first IO operation performed.

浅忆 2024-08-19 16:42:51

最大 10

设置要使用的并行度
在查询中。并行度为
最大并发数
执行将用于的任务
处理查询。

从这里:

MSDN

10 is maximum

Sets the degree of parallelism to use
in a query. Degree of parallelism is
the maximum number of concurrently
executing tasks that will be used to
process the query.

From here:

MSDN

枕梦 2024-08-19 16:42:51

看起来 PLINQ 调整了线程数。当我将上面的代码包装在 while(true) 循环中时,前两次迭代运行需要两秒,但第三次及以上只需要一秒。 PLINQ 知道核心处于空闲状态并增加了线程数量。感人的!

It appears PLINQ tunes the number of threads. When I wrapped the above code in a while(true) loop, the first two iteration took two seconds to run, but the third and above took only one second. PLINQ understood the cores are idle and upped the number of threads. Impressive!

送君千里 2024-08-19 16:42:51

我同意 Rory 的观点,但 IO 除外。尚未测试磁盘 IO,但网络 IO 在线程数较多的情况下肯定比 CPU 上的内核更有效。

简单的测试(对每个线程计数运行几次测试会更正确,因为网络速度不是恒定的,但仍然如此)来证明:

    [Test]
    public void TestDownloadThreadsImpactToSpeed()
    {
        var sampleImages = Enumerable.Range(0, 100)
            .Select(x => "url to some quite large file from good server which does not have anti DSS stuff.")
            .ToArray();            

        for (int i = 0; i < 8; i++)
        {
            var start = DateTime.Now;
            var threadCount = (int)Math.Pow(2, i);
            Parallel.For(0, sampleImages.Length - 1, new ParallelOptions {MaxDegreeOfParallelism = threadCount},
                         index =>
                             {
                                 using (var webClient = new WebClient())
                                 {
                                     webClient.DownloadFile(sampleImages[index],
                                                            string.Format(@"c:\test\{0}", index));
                                 }
                             });

            Console.WriteLine("Number of threads: {0}, Seconds: {1}", threadCount, (DateTime.Now - start).TotalSeconds);
        }
    }

使用带有 SSD 的 8 核机器从 CDN 获取 500x500px 图像的结果是:

线程数:1,秒:25.3904522
线程数:2,秒:10.8986233
线程数:4,秒:9.9325681
线程数:8,秒:3.7352137
线程数:16,秒数:3.3071892
线程数:32,秒数:3.1421797
线程数:64,秒:3.1161782
线程数:128,秒数:3.7272132

最后的结果有这样的时间,我认为首先是因为我们只需要下载 100 个图像:)

使用 8-64 个线程的时间差异并不是那么大,但这是在 8 核机器上。如果是 2 核机器(廉价的最终用户笔记本),我认为强制使用 8 线程会比在 8 核机器上强制使用 64 线程产生更大的影响。

I would agree to Rory, except IO. Haven't tested with disk IO, but network IO definitively may be more effective with more threads, than there are cores on CPU.

Simple test (it would be more correct to run test with each thread count several times, as network speed isn't constant, but still) to prove that:

    [Test]
    public void TestDownloadThreadsImpactToSpeed()
    {
        var sampleImages = Enumerable.Range(0, 100)
            .Select(x => "url to some quite large file from good server which does not have anti DSS stuff.")
            .ToArray();            

        for (int i = 0; i < 8; i++)
        {
            var start = DateTime.Now;
            var threadCount = (int)Math.Pow(2, i);
            Parallel.For(0, sampleImages.Length - 1, new ParallelOptions {MaxDegreeOfParallelism = threadCount},
                         index =>
                             {
                                 using (var webClient = new WebClient())
                                 {
                                     webClient.DownloadFile(sampleImages[index],
                                                            string.Format(@"c:\test\{0}", index));
                                 }
                             });

            Console.WriteLine("Number of threads: {0}, Seconds: {1}", threadCount, (DateTime.Now - start).TotalSeconds);
        }
    }

Result with 500x500px image from CDN using 8 core machine with SSD was:

Number of threads: 1, Seconds: 25.3904522
Number of threads: 2, Seconds: 10.8986233
Number of threads: 4, Seconds: 9.9325681
Number of threads: 8, Seconds: 3.7352137
Number of threads: 16, Seconds: 3.3071892
Number of threads: 32, Seconds: 3.1421797
Number of threads: 64, Seconds: 3.1161782
Number of threads: 128, Seconds: 3.7272132

Last result has such time i think firstly because we have to download only 100 images :)

Time differences using 8-64 threads isn't that big, but that is on 8 core machine. If it was 2 core machine (cheap enduser notebook), i think forcing to use 8 threads would have more impact, than on 8 core machine forcing to use 64 threads.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文