【问题标题】:Parallel.ForEach with lock, the performance of the loop is very slowParallel.ForEach with lock,循环的性能很慢
【发布时间】:2023-01-26 18:53:07
【问题描述】:

当我使用 foreach 循环或带锁的 Parallel.ForEach 时,数据正常输出,但是当我使用没有 lockParallel.ForEach 时,数据不一致并发生数据丢失。此外,如果我使用每个模型项作为 Parallel.ForEach 中的参数并删除模型,而不是模型 ApiFileItems,则输出是一致的并且没有数据丢失。

现在lock 我面临的问题是性能非常慢。 但是当我在没有锁的情况下使用Parallel.ForEach循环时,性能很快但是数据不一致并且发生数据丢失。现在我坚持了将近 4 天,没有得到任何提高性能的解决方案。

private static void ParallelExecution(JArray ContentNode,
    ApiFileItems apiFileItems, ApiTypeItem apiTypeItem)
{
    Parallel.Foreach(ContentNode.Values(), new ParallelOptions(){}, (rootNode) =>
    {
        lock (ContentNode)
        {
            if (rootNode.HasValues)
            {
                ParallelRootItemExecution(rootNode, apiFileItems, apiTypeItem);
            }
            else
            {
                //Log the message
            }
        }
    });
}

private static void ParallelRootItemExecution(JToken rootNode,
    ApiFileItems apiFileItems, ApiItemType apiItemType)
{
    Parallel.ForEach<JToken>(rootNode.Values(),
        new ParallelOptions() {MaxDegreeOfParallelism = 4}, (metaNode) =>
    {
        lock (rootNode)
        {
            bool foundValue = false;
            apiFileItems.relativeFilePath = metaNode["valueString"].ToString();
            if (!foundFolderItems.TryGetValue(apiFileItems.relativeFilePath,
                out foundValue))
            {
                foundFolderItems.TryAdd(apiFileItems.relativeFilePath, true);
                ParallelExecution((String.FormatapiFileItems.relativeGroupUrl,
                    apiFileItems.hostName, apiFileItems.publicationId,
                    apiFileItems.relativeFilePath), apiFileItems,apiItemType);
            }
        }
    });
}

不使用lock时会出现数据丢失,数据不一致。

【问题讨论】:

  • 那么,你同步/锁定全部的并行工作项,实际上强制每个工作项一个接一个地按顺序运行。与完全不使用 Parallel.Foreach 时一样。您需要确定工作项中可能同时访问相同资源/变量/属性/字段/集合/等的代码部分,并且仅同步/锁定这些部分,而不是整个工作项.如果几乎整个工作项目是
  • 如果没有锁,数据会以何种方式混乱(您期望什么,您得到了什么 - 堪称典范)? foundFolderItems 是什么类型?此外,嵌套Parallel.For*(大部分)从来都不是一个好主意。

标签: c# multithreading performance parallel-processing parallel.foreach


【解决方案1】:

Parallel.Foreach 允许并行执行循环的每次迭代。但是有了锁,同一时间只能运行一次迭代。这类似于同步代码,但性能下降,因为它必须管理锁。

一个简单的解决方案是使用经典的foreach 进行所有同步。

如果同步时性能不理想,那么就需要找出代码哪里不能并发,只对这部分进行加锁。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-29
    • 2014-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多