C# 使用多个Datareader连接进行批处理

C# 使用多个Datareader连接进行批处理,c#,.net,multithreading,datatable,datareader,C#,.net,Multithreading,Datatable,Datareader,我有一张有超过100000张唱片的桌子。我想读取数据,处理它们,如果处理成功,则删除该行,如果处理失败,则使用错误代码更新该行 我的方法是一次获取1000条记录,将其加载到datatable,然后将其传递给一个函数,该函数在5个并行线程中运行该进程。处理完前1000条记录后,打开一个新的DataReader并处理下1000条记录…依此类推 我的方法正确吗?我遇到的问题是代码运行良好,但1000条记录没有得到完全处理。大约有300条记录被处理,其余的保留下来。我做错了什么 using (SqlD

我有一张有超过100000张唱片的桌子。我想读取数据,处理它们,如果处理成功,则删除该行,如果处理失败,则使用错误代码更新该行

我的方法是一次获取1000条记录,将其加载到datatable,然后将其传递给一个函数,该函数在5个并行线程中运行该进程。处理完前1000条记录后,打开一个新的DataReader并处理下1000条记录…依此类推

我的方法正确吗?我遇到的问题是代码运行良好,但1000条记录没有得到完全处理。大约有300条记录被处理,其余的保留下来。我做错了什么

 using (SqlDataReader rdr = cmd.ExecuteReader) {
    if (rdr.HasRows) {
        Datatable dt = new Datatable();
        dt.Load(rdr);
        //process data
        results = Process(dt);
    }
}

public List<string> Process(Datatable dt) {
    var options = new ParallelOptions() {
    MaxDegreeOfParallelism = 5
    }
    List<string> results = new List<string>();
    
    Parallel.ForEach(dt.Rows.Cast<DataRow>(), options, (trans) => {
        //process and then delete/update row
        ....
        results.Add(transResult);
    });
    return results
}
使用(SqlDataReader rdr=cmd.ExecuteReader){
if(rdr.HasRows){
Datatable dt=新的Datatable();
dt.荷载(rdr);
//过程数据
结果=过程(dt);
}
}
公共列表过程(数据表dt){
var options=new ParallelOptions(){
MaxDegreeOfParallelism=5
}
列表结果=新列表();
Parallel.ForEach(dt.Rows.Cast(),options,(trans)=>{
//处理,然后删除/更新行
....
结果。添加(transResult);
});
返回结果
}

线程共享相同的资源,因此会导致dbContext出现问题。所以最好是并行地执行lock.ForEach作为

    Parallel.ForEach(dt.Rows.Cast<DataRow>(), options, (trans) => {
        var obj=new object();
    lock(obj)
            {
            //...your processing
            }
        });
Parallel.ForEach(dt.Rows.Cast(),options,(trans)=>{
var obj=新对象();
锁(obj)
{
//…您的处理
}
});

同时从多个线程调用
results
上的
Add
是不安全的。并行作业完成后,可以使用
ConcurrentBag
并调用
ToList()
,也可以使用
lock
语句包装
Add
。这种方法是错误的,原因有几个<代码>并行。ForEach仅用于使用所有可用内核处理大量内存中的数据,而不用于并行运行异步IO操作。无论
处理然后删除/更新行
做什么,在某个时候它都会与数据库通信,一次一行,在等待数据库响应时阻塞CPU核心。您执行哪种处理?这很重要。您可以使用数据流类(如TransformBlock、ActionBlock和BatchBlock)读取流中的源数据,处理每一行并在将结果批量写入数据库之前对其进行批处理,从而避免单个行修改所需的网络往返。您在做什么处理?这一切都可以用SQL完成吗@PanagiotisKanavos lambda中没有IO,它正在内存中执行一个
数据表
//进程,然后删除/更新行
必须从循环中删除锁定对象的创建。那么它应该会起作用,但它可能会对性能产生很大影响。