我有这段代码:
// positions is a List<Position>
Parallel.ForEach(positions, (position) =>
{
DeterminePostPieceIsVisited(position, postPieces);
});
private void DeterminePostPieceIsVisited(Position position, IEnumerable<Postpieces> postPieces)
{
foreach (var postPiece in postPieces)
{
if (postPiece.Deliverd)
continue;
var distanceToClosestPosition = postPiece.GPS.Distance(position.GPS);
postPiece.Deliverd = distanceToClosestPosition.HasValue && IsInRadius(distanceToClosestPosition.Value);
}
}
}
我知道50个帖子必须将属性Deliverd
设置为true。但是,在运行此代码时,我会改变结果。有时我得到44,当我再次运行它时,我得到47.结果是执行不同。
当我使用普通的foreach循环运行此代码时,我得到了预期的结果。所以我知道方法DeterminePostPieceIsVisited
的实现是正确的。
有人可以向我解释为什么每次执行此代码时使用Parallel foreach会给我不同的结果吗?
答案 0 :(得分:3)
我认为你已经试图避免竞争,但仍有一个 - 如果两个线程同时检查相同的postPiece
,他们可能两者观察Deliverd
(原文如此)是false
,然后评估它是否已被传递到position
(每个线程的一个不同值),并且都试图为{{1}设置一个值 - 我经常猜测,其中一个人会尝试将其设置为Deliverd
。简单修复:
false
顺便说一下:
当我使用普通的foreach循环运行此代码时,我得到了预期的结果。所以我知道方法
private void DeterminePostPieceIsVisited(Position position, IEnumerable<Postpieces> postPieces) { foreach (var postPiece in postPieces) { if (postPiece.Deliverd) continue; var distanceToClosestPosition = postPiece.GPS.Distance(position.GPS); var delivered = distanceToClosestPosition.HasValue && IsInRadius(distanceToClosestPosition.Value); if(delivered) postPiece.Deliverd = true; } }
的实现是正确的。
正确的陈述是“我知道我的实现是正确的用于单线程访问” - 你没有建立的是该方法对于从多个线程调用是安全的。 / p>
答案 1 :(得分:0)
我已用ConcurrentBag<T>
解决了我的问题。这是我现在使用的:
var concurrentPostPiecesList = new ConcurrentBag<Postpiece>(postPieces);
Parallel.ForEach(positions, (position) =>
{
DeterminePostPieceIsVisited(position, concurrentPostPiecesList);
});
private void DeterminePostPieceIsVisited(Position position, ConcurrentBag<Postpieces> postPieces)
{
foreach (var postPiece in postPieces)
{
if (postPiece.Deliverd)
continue;
var distanceToClosestPosition = postPiece.GPS.Distance(position.GPS);
postPiece.Deliverd = distanceToClosestPosition.HasValue && IsInRadius(distanceToClosestPosition.Value);
}
}