Parallel.For 中的那些列表是安全线程吗?
Are those Lists safe thread in Parallel.For?
我必须从 Parallel.ForEach
中删除 lock 对象。我应该使用 ConcurrentBag
还是直接删除它?没有 lock 对象是线程安全的吗?
results
是 List<>
.
Parallel.ForEach(entityList, options,
() =>
{
List<Customer> childrenResult = new List<Customer>();
return childrenResult;
},
(childrenObject, loopState, childrenResult) =>
{
childrenResult.AddRange(currentChildrenManager.Prepare(childrenObject, currentAnalyticalDataHolder, () => loopState.IsStopped, out childrenAllData));
return childrenResult;
},
(childrenResult) =>
{
lock (lockingObject)
{
if (childrenResult == null)
results.AddRange(new List<Customer>());
else if (currentChildrenManager.RowOrFilteredRowLimitation == null)
results.AddRange(childrenResult);
else
{
int leftCount = currentChildrenManager.RowOrFilteredRowLimitation.GetRelativRowLimitation(provider.IsForGenerationTime) - results.Count();
if (leftCount > 0)
{
if (childrenResult.Count() > leftCount)
{
tAllData = currentChildrenManager.OnlyFirst;
results.AddRange(childrenResult.Take(leftCount));
}
else
results.AddRange(childrenResult);
}
else
{
tAllData = currentChildrenManager.OnlyFirst;
}
}
}
});
我假设您提供的代码使用了重载,它接受一个 localInit
值并分别使用 localFinally
Func<T>
和 Action<T>
看起来像这样:
public static ParallelLoopResult ForEach<TSource, TLocal>(
IEnumerable<TSource> source,
ParallelOptions parallelOptions,
Func<TLocal> localInit,
Func<TSource, ParallelLoopState, TLocal, TLocal> body,
Action<TLocal> localFinally
)
锁仍然是强制性的,因为最后的操作必须并行地向底层列表添加项目。您 可以 使用 ConcurrentBag<T>
进行最后的串联,但我建议您对这两种方式进行基准测试,看看哪种方式性能更好。
也许另一种更适合您的方法是使用 PLINQ。这样,您可以并行操作多个项目,并且仅在最后使用 ToList
创建包含您的结果的 List<T>
:
var result = entityList.AsParallel()
.Select(childObject =>
currentChildrenManager.Prepare(
childObject, currentAnalyticalDataHolder, out childrenAllData))
.ToList();
// Modify the list further if needed.
我必须从 Parallel.ForEach
中删除 lock 对象。我应该使用 ConcurrentBag
还是直接删除它?没有 lock 对象是线程安全的吗?
results
是 List<>
.
Parallel.ForEach(entityList, options,
() =>
{
List<Customer> childrenResult = new List<Customer>();
return childrenResult;
},
(childrenObject, loopState, childrenResult) =>
{
childrenResult.AddRange(currentChildrenManager.Prepare(childrenObject, currentAnalyticalDataHolder, () => loopState.IsStopped, out childrenAllData));
return childrenResult;
},
(childrenResult) =>
{
lock (lockingObject)
{
if (childrenResult == null)
results.AddRange(new List<Customer>());
else if (currentChildrenManager.RowOrFilteredRowLimitation == null)
results.AddRange(childrenResult);
else
{
int leftCount = currentChildrenManager.RowOrFilteredRowLimitation.GetRelativRowLimitation(provider.IsForGenerationTime) - results.Count();
if (leftCount > 0)
{
if (childrenResult.Count() > leftCount)
{
tAllData = currentChildrenManager.OnlyFirst;
results.AddRange(childrenResult.Take(leftCount));
}
else
results.AddRange(childrenResult);
}
else
{
tAllData = currentChildrenManager.OnlyFirst;
}
}
}
});
我假设您提供的代码使用了重载,它接受一个 localInit
值并分别使用 localFinally
Func<T>
和 Action<T>
看起来像这样:
public static ParallelLoopResult ForEach<TSource, TLocal>(
IEnumerable<TSource> source,
ParallelOptions parallelOptions,
Func<TLocal> localInit,
Func<TSource, ParallelLoopState, TLocal, TLocal> body,
Action<TLocal> localFinally
)
锁仍然是强制性的,因为最后的操作必须并行地向底层列表添加项目。您 可以 使用 ConcurrentBag<T>
进行最后的串联,但我建议您对这两种方式进行基准测试,看看哪种方式性能更好。
也许另一种更适合您的方法是使用 PLINQ。这样,您可以并行操作多个项目,并且仅在最后使用 ToList
创建包含您的结果的 List<T>
:
var result = entityList.AsParallel()
.Select(childObject =>
currentChildrenManager.Prepare(
childObject, currentAnalyticalDataHolder, out childrenAllData))
.ToList();
// Modify the list further if needed.