基本上,我有一个对象的集合,我把它切成小集合,并且同时在每个小集合上的一个线程上做一些工作。
int totalCount = SomeDictionary.Values.ToList().Count;
int singleThreadCount = (int)Math.Round((decimal)(totalCount / 10));
int lastThreadCount = totalCount - (singleThreadCount * 9);
Stopwatch sw = new Stopwatch();
Dictionary<int,Thread> allThreads = new Dictionary<int,Thread>();
List<rCode> results = new List<rCode>();
for (int i = 0; i < 10; i++)
{
int count = i;
if (i != 9)
{
Thread someThread = new Thread(() =>
{
List<rBase> objects = SomeDictionary.Values
.Skip(count * singleThreadCount)
.Take(singleThreadCount).ToList();
List<rCode> result = objects.Where(r => r.ZBox != null)
.SelectMany(r => r.EffectiveCBox, (r, CBox) => new rCode
{
RBox = r,
// A Zbox may refer an object that can be
// shared by many
// rCode objects even on different threads
ZBox = r.ZBox,
CBox = CBox
}).ToList();
results.AddRange(result);
});
allThreads.Add(i, someThread);
someThread.Start();
}
else
{
Thread someThread = new Thread(() =>
{
List<rBase> objects = SomeDictionary.Values
.Skip(count * singleThreadCount)
.Take(lastThreadCount).ToList();
List<rCode> result = objects.Where(r => r.ZBox != null)
.SelectMany(r => r.EffectiveCBox, (r, CBox) => new rCode
{
RBox = r,
// A Zbox may refer an object that
// can be shared by many
// rCode objects even on different threads
ZBox = r.ZBox,
CBox = CBox
}).ToList();
results.AddRange(result);
});
allThreads.Add(i, someThread);
someThread.Start();
}
}
sw.Start();
while (allThreads.Values.Any(th => th.IsAlive))
{
if (sw.ElapsedMilliseconds >= 60000)
{
results = null;
allThreads.Values.ToList().ForEach(t => t.Abort());
sw.Stop();
break;
}
}
return results != null ? results.OrderBy(r => r.ZBox.Name).ToList():null;
所以,我的问题是SOMETIMES,我在返回结果之前执行OrderBy操作时得到一个空引用异常,我无法确定异常在哪里,我按回来,单击执行此操作的相同按钮再次操作相同的数据,它的工作原理!! ..如果有人可以帮助我确定这个问题,我将不仅仅是感激不尽。注意:Zbox可能会引用一个对象,即使在不同的线程上也可以被许多rCode对象共享,这可能是个问题吗? 因为我无法在测试中确定这一点,因为发生的错误不是确定性的。
答案 0 :(得分:2)
虽然我不同意答案,但在所选答案中找到了错误。您应该切换到使用并发集合。在你的情况下是ConcurrentBag或ConcurrentQueue。其中一些(部分)无锁定以获得更好的性能。并且它们提供更多可读性和更少的代码,因为您不需要手动锁定。
如果您不使用手动创建的线程和手动分区,您的代码的大小也会减半,可读性也会增加一倍;
Parallel.ForEach(objects, MyObjectProcessor);
public void MyObjectProcessor(Object o)
{
// Create result and add to results
}
如果要使用Parallel.ForEach限制线程数,请使用ParallelOptions对象............
答案 1 :(得分:1)
嗯,这里有一个明显的问题:
results.AddRange(result);
您要从多个线程更新列表。尝试使用锁:
object resultsLock = new object(); // globally visible
...
lock(resultsLock)
{
results.AddRange(result);
}
答案 2 :(得分:0)
我想结果中的问题= null
while (allThreads.Values.Any(th => th.IsAlive))
{ if (sw.ElapsedMilliseconds >= 60000) { results = null; allThreads.Values.ToList().ForEach(t => t.Abort());
如果线程未超过60000毫秒,则结果将变为null,并且您无法调用results.OrderBy(r =&gt; r.ZBox.Name).ToList();它抛出异常
你应该添加类似的东西
if (results != null)
return results.OrderBy(r => r.ZBox.Name).ToList();
else
return null;