带有线程的c#实体框架

wog*_*les 3 c# multithreading entity-framework thread-safety

我必须在数百万行数据上运行一次C#计算,并将结果保存在另一个表中.我在几年内没有使用过C#中的线程.我正在使用.NET v4.5和EF v5.

原始代码的含义如下:

public static void Main()
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    Entities db = new Entities();
    DoCalc(db.Clients.ToList());
    sw.Stop();
    Console.WriteLine(sw.Elapsed);
}

private static void DoCalc(List<Client> clients)
{
Entities db = new Entities();    
    foreach(var c in clients)
    {
       var transactions = db.GetTransactions(c);
       var result = calulate(transactions); //the actual calc
       db.Results.Add(result);
       db.SaveChanges();
    }    
}
Run Code Online (Sandbox Code Playgroud)

以下是我对多线程的尝试:

private static int numberOfThreads = 15;

public static void Main()
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    Entities db = new Entities();

    var splitUpClients = SplitUpClients(db.Clients());

    Task[] allTasks = new Task[numberOfThreads];

    for (int i = 0; i < numberOfThreads; i++)
    {               
        Task task = Task.Factory.StartNew(() => DoCalc(splitupClients[i]));
        allTasks[i] = task;             
     }  

    Task.WaitAll(allTasks);             
    sw.Stop();
    Console.WriteLine(sw.Elapsed);
}

private static void DoCalc(List<Client> clients)
{
Entities db = new Entities();    
    foreach(var c in clients)
    {
       var transactions = db.GetTransactions(c);
       var result = calulate(transactions);
       db.Results.Add(result);
       db.SaveChanges();
    }    
}

//splits the list of clients into n subgroups
private static List<List<Client>> SplitUpClients(List<Client> clients)
{
    int maxPerGroup = (int)Math.Ceiling((double)clients.Count() / numberOfThreads);

    return ts.Select((s, i) => new { Str = s, Index = i }).
                        GroupBy(o => o.Index / maxPerGroup, o => o.Str).
                        Select(coll => coll.ToList()).
                        ToList();           
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:

这是否是安全和正确的方法,并且有任何明显的缺点(特别是关于EF)?

另外,如何找到最佳线程数?这是更多的好处吗?

Ste*_*ven 7

实体框架DbContextObjectContext不是线程安全的.所以你不应该在多个线程上使用它们.

虽然看起来你只是将实体传递给其他线程,但是当涉及延迟加载时,很容易出错.这意味着在实体中,实体将回调上下文以获取更多数据.

因此,我建议将实体列表转换为只需要计算所需数据的特殊不可变数据结构列表.那些不可变结构不应该回调到上下文中,不应该改变.执行此操作时,将它们传递给其他线程进行计算是安全的.