我必须在某处做错事,因为我在我的concurrentbag中得到了重复的项目,这里是事件链
var listings = new ConcurrentBag<JSonListing>();
Parallel.ForEach(Types, ParallelOptions, (type, state) =>
{
...
status = ProcessType(listings, status, type, state);
....
});
private GeocodeResults ProcessType(ConcurrentBag<JSonListing> listings, GeocodeResults status, XElement type, ParallelLoopState state)
{
....
AddListingsToList(results, type, listings);
....
}
private void AddListingsToList(dynamic results, XElement type, ConcurrentBag<JSonListing> listings)
{
var typeMustMatch = type.Attribute("TypeMustMatch").Value;
var typeID = Convert.ToInt32(type.Attribute("ID").Value);
foreach (var result in results.results)
{
var foundListing = listings.SingleOrDefault(x => x.ID == result.id);
if (foundListing != null)
{
var typeIDs = foundListing.TypeIDs.Split("|".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).ToList();
if (!typeIDs.Contains(typeID.ToString()))
{
foundListing.TypeIDs += "|" + typeID;
}
}
else
{
var listing = new JSonListing { ID = result.id, ReferenceNumber = result.reference, TypeIDs = typeID.ToString(), TypeMustMatch = typeMustMatch };
listings.Add(listing);
}
}
}
添加列表应该保证如果元素存在,则不要添加另一个相同的ID,而是更新一些属性。 现在我得到的错误是
System.InvalidOperationException:Sequence包含多个匹配元素
在System.Linq.Enumerable.SingleOrDefault [TSource](IEnumerable`1 source,Func`2谓词)
at LocalSearch.Processor.CityProcessor.AddListingsToList(Object results,XElement type,ConcurrentBag`1 listing)在d:\ Projects \ ListingLocator2 \ Code \ LocalSearch.Processor \ Processors.cs:第310行
在CallSite.Target(Closure,CallSite,CityProcessor,Object,XElement,ConcurrentBag`1)
在LocalSearch.Processor.CrocessProcessor.ProcessType(ConcurrentBag`1列表,GeocodeResults状态,XElement类型,ParallelLoopState状态)中的d:\ Projects \ ListingLocator2 \ Code \ LocalSearch.Processor \ Processors.cs:第249行 在LocalSearch.Processor.CityProcessor。&lt;&gt; c__DisplayClass4.b__0(XElement类型,ParallelLoopState状态)在d:\ Projects \ ListingLocator2 \ Code \ LocalSearch.Processor \ Processors.cs:第137行
答案 0 :(得分:18)
ConcurrentBag
保证其上的每个操作在单独考虑时都是线程安全的。它不保证连续的多个操作将被视为原子组。
因此,您的代码具有竞争条件:您检查行李是否已包含某个项目X,但是两个线程可以同时运行测试,确定该项目不存在,然后继续添加它。最终结果:该物品的两个副本最终放入包中。
通过使用ConcurrentDictionary
代替并利用{em> 原子的TryAdd
方法,看起来您的用例会更好。或者你可以在包里放一个lock()
来使块内的所有内容都以原子方式运行,但是你不需要并发收集,而是可以使用直接List
。
答案 1 :(得分:8)
这并不意味着Concurrent Bag不是线程安全的,它只是意味着你的代码不是
您正在检查并发行李中的值,然后在前一次检查失败时添加新项目。
但是,由于代码中没有锁,因此两个作业可以同时执行以下操作;
THREAD 1 THREAD 2
=-=-=-=-=-=-=-=-=-=-=-=-
Check Exists
Check Exists
Add New
Add New
您需要锁定支票并添加例程。