我正在
Parallel.ForEach
语句中编写一些代码。每个线程都应该做一些工作,然后将结果插入列表中。当列表达到 %20 的计数时,它应该将项目插入数据库中,因为我不希望每个线程打开一个新连接并插入一项。
显然,使用下面的代码,许多线程正在修改我的列表,并且出现错误
Collection was modified
。我也不能使用 Lock
,因为如果每个线程都必须等待锁来修改列表,我就会失去并行化的好处。
实现上述目标的最佳方法是什么?我尝试暂停 Foreach 然后恢复,但没有成功。
private ItemsDAL _itemsDal = new ItemsDAL();
public void Run()
{
List<Item> items = new List<Item>();
for (int i = 0; i < 1500; i++)
{
items.Add(new Item()
{
Details = "Test " + i
});
}
Parallel.ForEach(items, (oneItem) =>
{
Console.WriteLine("Adding item with Details " + oneItem.Details);
_itemsDal.InsertToDatabase(oneItem);
});
}
DAL 班
public class ItemsDAL
{
object _lock = new object();
private List<Item> _itemsToInsert = new List<Item>();
public void InsertToDatabase(Item item)
{
_itemsToInsert.Add(item);
if (_itemsToInsert.Count >= 20)
{
//Add to database in bulk (Blocs of 20)
using (ForeachContext db = new ForeachContext())
{
foreach (var itemToInsert in _itemsToInsert)
{
db.Items.Add(itemToInsert);
}
db.SaveChanges();
}
_itemsToInsert.Clear();
}
}
}
我也不能使用 Lock,因为如果每个线程都必须等待锁来修改列表,我就会失去并行化的好处。
其实不然。将项目添加到列表中非常快。并且锁定该操作不会失去线程在插入列表之前“做一些工作”的部分的并行化的任何好处。
真的,你可以简单地使用
lock(_lock)
块来覆盖InsertToDatabase
的整个身体。