【问题标题】:Controlling number of threads using AsParallel or Parallel.ForEach使用 AsParallel 或 Parallel.ForEach 控制线程数
【发布时间】:2013-11-25 20:15:34
【问题描述】:

我有一个庞大的集合,我必须在其中执行特定任务(这涉及调用 wcf 服务)。我想控制线程数,而不是直接使用 Parallel.ForEach。在这里,我有 2 个选项: 我在下面使用来对数据进行分区:

List<MyCollectionObject> MyCollection = new List<MyCollectionObject>();
 public static IEnumerable<List<T>> PartitionMyData<T>(this IList<T> source, Int32 size)
        {
            for (int i = 0; i < Math.Ceiling(source.Count / (Double)size); i++)
            {
                yield return new List<T>(source.Skip(size * i).Take(size));
            }
        }

选项 1:

MyCollection.PartitionMyData(AutoEnrollRequests.Count()/threadValue).AsParallel().AsOrdered()
                                        .Select(no => InvokeTask(no)).ToArray();

 private void InvokeTask(List<MyCollectionObject> requests)
{
   foreach(MyCollectionObject obj in requests)
  {
    //Do Something
  }
}

选项2:

MyCollection.PartitionMyData(threadValue).AsOrdered()
                                        .Select(no => InvokeTask(no)).ToArray();

private void InvokeTask(List<MyCollectionObject> requests)
{
    Action<MyCollectionObject> dosomething = 
    {
    }
    Parallel.ForEach(requests,dosomething)
}

如果我的集合中有 16 个对象,据我所知,Option1 将启动 4 个线程,每个具有 4 个对象的线程将被同步处理。 选项 2 将启动 4 个线程,每个线程有 1 个对象,处理它们,然后再次启动 4 个线程。 谁能建议哪个选项更好?

附: 我知道 .Net 框架会进行线程池,我们不需要控制线程的数量,但由于某些设计决定我们想要使用它。

提前致谢, 罗希特

【问题讨论】:

    标签: c# multithreading


    【解决方案1】:

    我想控制线程数而不是直接使用Parallel.ForEach

    如果您将this callParallelOptions 对象一起使用,您可以控制Parallel.ForEach 中的线程数:

    Parallel.ForEach(requests,
                     new ParallelOptions(){MaxDegreeOfParallelism = 4}, //change here
                     dosomething)
    

    【讨论】:

    • 嗨朱利安,这是一个旧帖子,但在这里需要你的帮助。我使用了上述选项,但现在有时会出现 OutOfMemory Exception。我们监控了服务器上的内存消耗,但它低于 60%。堆栈跟踪显示:Exception Info: System.OutOfMemoryException Stack: at System.Threading.ThreadPoolWorkQueue.EnsureCurrentThreadHasQueue() at System.Threading.ThreadPoolWorkQueue.Dispatch() at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
    【解决方案2】:

    这里不可能给出 A 或 B 的答案。这取决于太多的未知数。

    我假设您想要最快的方法。要查看哪个更好,请同时在目标环境(或您可以获得的最接近的近似值)上运行,然后查看哪个完成速度最快。

    【讨论】:

    • 嗨詹姆斯,这是一个旧帖子,但在这里需要你的帮助。我使用了 Julian 下面提到的选项,但现在有时会出现 OutOfMemory Exception。我们监控了服务器上的内存消耗,但它低于 60%。堆栈跟踪显示:Exception Info: System.OutOfMemoryException Stack: at System.Threading.ThreadPoolWorkQueue.EnsureCurrentThreadHasQueue() at System.Threading.ThreadPoolWorkQueue.Dispatch() at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
    • OutOfMemory 异常意味着进程无法分配内存。如果服务器有足够的内存,那么我认为您很可能正在运行为 x86 编译的 .NET 代码,并且已经超过了 2Gb 可用内存。检查进程而不是服务器的内存消耗。如果您不确定 x86,请从 windows SDK 对您的二进制文件运行 corflags.exe(安装到程序文件中的 windows sdk 文件夹中)以检查它是否为 32 位。
    • @user2159471 同样,如果您提出有关该内存异常的新问题,您可能会找到更多帮助
    • 嗨,詹姆斯,感谢您的见解,到目前为止,所有这些都对您有所帮助。该进程只有 32 位,我们已经能够在一个下游进程中追踪到 2 个内存泄漏。但我们面临的令人沮丧的部分是有时应用程序在仅 100 条记录后中止,有时它处理 2500 条记录。如果将 ParallleOption 修改为使用单线程,是否会有帮助。 [内存泄漏不应超过 2 GB 内存,我们需要一些时间才能在 prod 环境中修复这些问题。] 另外请您看看我发布的代码@:
    • 此外,内存泄漏不应达到 2 GB 内存,我们需要一些时间才能在 prod 环境中修复这些问题。所以暂时我们迫切需要一些临时修复。将其转换为 64 位进程是一种选择,但需要 100% 确定它会工作。我很怀疑,因为有时应用程序会在 100 条记录后中止。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-16
    • 1970-01-01
    • 2012-01-15
    • 1970-01-01
    • 1970-01-01
    • 2018-04-30
    相关资源
    最近更新 更多