Parallel.ForEach 和 SQL 批量插入 20 个

问题描述 投票:0回答:1

我正在

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();
        }
    }
}
c# sql-server entity-framework thread-safety parallel.foreach
1个回答
0
投票

我也不能使用 Lock,因为如果每个线程都必须等待锁来修改列表,我就会失去并行化的好处。

其实不然。将项目添加到列表中非常快。并且锁定该操作不会失去线程在插入列表之前“做一些工作”的部分的并行化的任何好处。

真的,你可以简单地使用

lock(_lock)
块来覆盖
InsertToDatabase
的整个身体。

© www.soinside.com 2019 - 2024. All rights reserved.