【问题标题】:ParallelOptions with MaxDegreeOfParallelism and actual number of threads具有 MaxDegreeOfParallelism 和实际线程数的 ParallelOptions
【发布时间】:2021-02-16 15:16:13
【问题描述】:

您好,我正在使用 MaxDegreeOfParallelism 方法的不同值进行“动态”多线程处理,但是每当我尝试更改大于 1 的 MaxDegreeOfParallelism 的值时,它会在控制台中显示该程序使用的线程数超过了我分配的线程数。

public static string DoMultipleTasks(int threads, List<string> inputList)
{            
    ParallelOptions po = new ParallelOptions();          
    po.MaxDegreeOfParallelism = threads;
    Parallel.ForEach(inputList, po,  values =>
    {
        Console.WriteLine(" Name: {0}, Thread Id= {1}", values, Thread.CurrentThread.ManagedThreadId);
    });            
    return null;
}

输出:

【问题讨论】:

    标签: c# .net multithreading parallel-processing console-application


    【解决方案1】:

    MaxDegreeOfParallelism 指定可以同时运行多少个线程(或者更确切地说是任务)。它没有指定应该是哪些线程。

    来自docs

    获取或设置此 ParallelOptions 实例启用的最大并发任务数。

    在您执行Parallel.ForEach 期间,您可能会在许多不同的线程上运行(因此涉及许多不同的线程ID)。这取决于底层线程调度程序。

    但是,您可以保证您的代码块最多同时执行MaxDegreeOfParallelism

    虽然您基本上已经有了一个示例,但这里有一个稍微修改过的代码版本来说明我的意思。

    var dict = new ConcurrentDictionary<int, string>();
    var po = new ParallelOptions { MaxDegreeOfParallelism = 3 };
    int count = 0, maxval = 0;
    Parallel.ForEach(Enumerable.Range(1, 10000000), po, (d) =>
    {
        Interlocked.Increment(ref count);
        dict.AddOrUpdate(Thread.CurrentThread.ManagedThreadId, "", (id, old) => old);
    
        lock (dict)
        {
            maxval = Math.Max(maxval, count);
        }
        Interlocked.Decrement(ref count);
    });
    
    Console.WriteLine("Count: " + count);
    Console.WriteLine("Max: " + maxval);
    Console.WriteLine("Thread ids: " + String.Join(", ", dict.Select(d => d.Key)));
    

    它应该会产生类似这样的输出:

    计数:0
    最大:3
    线程 ID:1、4、5、6、7、8、9

    无论您运行多少次此代码,最大值都不应超过 3。另一方面,线程 ID 会经常更改。

    【讨论】:

    • 不确定否决票。让我知道是否有任何不清楚的地方。 :)
    • 感谢您的回答,这不是我的反对意见。现在一切都清楚了,但我仍然很困惑为什么程序在多线程上比在 1 个线程上运行得慢。
    • 当您想要加快代码的执行速度时,多线程并不总是答案。在您的示例中,您调用 Console.WriteLine 必须将写入同步到控制台,以免产生乱码结果。因此,即使您使用多个线程,它们最终都会相互等待。所以你增加了更多的开销(线程管理)只是为了同步打印消息。
    • 一般来说,如果你需要大量的 I/O 操作,多线程不应该是你的首选。另一方面,如果您需要对集合中的每个值执行大量 CPU 繁重的工作(这就是花费时间的地方),那么线程可能是加速它的好选择。
    • 赞成。但是在一小段代码中使用三种不同的同步机制可能有点太匹配了(并发集合+lock+Interlocked)。而且它仍然不是线程安全的。在maxval = Math.Max(maxval, count); 行中,您应该使用先前Interlocked 调用返回的本地count,而不是访问主动变异的共享值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-14
    • 2018-01-23
    • 2017-10-09
    • 2017-06-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多