C# TPL数据流管道意外结束
我是TPL数据流新手,这是我的第一条管道 我正在将1M行推到C# TPL数据流管道意外结束,c#,task-parallel-library,C#,Task Parallel Library,我是TPL数据流新手,这是我的第一条管道 我正在将1M行推到EmpresasBuffer。在1000个批次中,EmpresasBuffer将数据发送到SaveBlock,并将其保存到数据库中。保存后,ExitBlock显示到现在为止处理了多少行 这适用于较少的行。如果我尝试推送10000行,它会像预期的那样工作,但是对于1M行,它会默默地失败 检查代码我看到SaveBlock和ExitBlock被设置为Completed,但是,这发生在调用EmpresasBuffer.Complete()之前
EmpresasBuffer
。在1000个批次中,EmpresasBuffer
将数据发送到SaveBlock
,并将其保存到数据库中。保存后,ExitBlock
显示到现在为止处理了多少行
这适用于较少的行。如果我尝试推送10000行,它会像预期的那样工作,但是对于1M行,它会默默地失败
检查代码我看到SaveBlock
和ExitBlock
被设置为Completed,但是,这发生在调用EmpresasBuffer.Complete()
之前
这是创建管道的代码:
var EmpresasBuffer = new BatchBlock<EmpresaModel>(1000,
new GroupingDataflowBlockOptions {
EnsureOrdered = false,
BoundedCapacity = 10000 });
var SaveBlock = new TransformBlock<EmpresaModel[], int>(
async x => await SalvarEmpresaAsync(x),
new ExecutionDataflowBlockOptions {
EnsureOrdered = false,
MaxDegreeOfParallelism = 32,
BoundedCapacity = 10000 });
car ExitBlock = new ActionBlock<int>(x => {
Console.WriteLine($"[{DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss")}] Registros Importados: {TotalRows += x}");
});
EmpresasBuffer.LinkTo(SaveBlock, new DataflowLinkOptions { PropagateCompletion = true });
SaveBlock.LinkTo(ExitBlock, new DataflowLinkOptions { PropagateCompletion = true });
我的代码怎么了
这是Salvarempresasync的代码:
public static async Task<int> SalvarEmpresaAsync(EmpresaModel[] modelArray)
{
using (var Connection = new SqlConnection(ConnectionString))
{
Connection.Open();
var TaskEmpresa = BulkInsert<EmpresaModel>(Connection, "Empresas", modelArray, PropertiesEmpresa);
var TaskQuadroSocietario = BulkInsert<QuadroSocietarioModel>(Connection, "QuadroSocietario", modelArray.SelectMany(x => x.QuadrosSocietarios).AsEnumerable(), PropertiesQuadroSocietario);
await TaskEmpresa;
await TaskQuadroSocietario;
}
return modelArray.Length;
}
public static async Task BulkInsert<T>(SqlConnection connection, string tableName, IEnumerable<T> data, string[] columns) where T: class
{
using (var BulkCopy = new SqlBulkCopy(connection))
using (var reader = ObjectReader.Create(data, columns))
{
foreach (string property in columns)
{
BulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping(property, property));
}
BulkCopy.DestinationTableName = tableName;
await BulkCopy.WriteToServerAsync(reader);
}
}
公共静态异步任务salvarempresasync(EmpresaModel[]modelArray)
{
使用(var连接=新的SqlConnection(ConnectionString))
{
Connection.Open();
var TaskEmpresa=BulkInsert(连接,“Empresas”、modelArray、PropertiesEmpresa);
var TaskQuadroSocietario=BulkInsert(连接,“QuadroSocietario”,modelArray.SelectMany(x=>x.quadrosocietarios.AsEnumerable(),属性QuadroSocietario);
等待任务执行;
等待任务完成;
}
返回modelArray.Length;
}
公共静态异步任务BulkInsert(SqlConnection连接、字符串tableName、IEnumerable数据、字符串[]列),其中T:class
{
使用(var-BulkCopy=new-SqlBulkCopy(连接))
使用(var reader=ObjectReader.Create(数据、列))
{
foreach(列中的字符串属性)
{
添加(新的SqlBulkCopyColumnMapping(属性,属性));
}
BulkCopy.DestinationTableName=表名;
等待BulkCopy.WriteToServerAsync(读卡器);
}
}
您是否看到某些东西不工作?Salvarempresasync做什么?如果它失败,或者使用catch{}
隐藏错误,您将不会注意到任何错误。没有调用Complete()
或等待ExitBlock.Completionl
。Salvarempresasync
引发的任何错误都将在最终的Wait
BoundedCapacity=10000
中被收回?在10001发生了什么?在这段代码中,唯一可以抛出的是丢失的代码。也许salvarempresasync
有错误?也许程序从不等待完成?也许应用程序内存不足是因为SaveBlock
缓存了10000个缓冲区,每个缓冲区包含1000个项目,在内存中保留了1000万行??并尝试在同一数据库中执行32次并发批插入?这保证了数据库中的阻塞。假设您使用SqlBulkCopy,请完全删除MaxDop参数,并使用一个合理的BoundedCapacity
数字,尽管只要1
就可以了-如果SqlBulkCopy一直很慢,则缓冲几乎没有什么好处
public static async Task<int> SalvarEmpresaAsync(EmpresaModel[] modelArray)
{
using (var Connection = new SqlConnection(ConnectionString))
{
Connection.Open();
var TaskEmpresa = BulkInsert<EmpresaModel>(Connection, "Empresas", modelArray, PropertiesEmpresa);
var TaskQuadroSocietario = BulkInsert<QuadroSocietarioModel>(Connection, "QuadroSocietario", modelArray.SelectMany(x => x.QuadrosSocietarios).AsEnumerable(), PropertiesQuadroSocietario);
await TaskEmpresa;
await TaskQuadroSocietario;
}
return modelArray.Length;
}
public static async Task BulkInsert<T>(SqlConnection connection, string tableName, IEnumerable<T> data, string[] columns) where T: class
{
using (var BulkCopy = new SqlBulkCopy(connection))
using (var reader = ObjectReader.Create(data, columns))
{
foreach (string property in columns)
{
BulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping(property, property));
}
BulkCopy.DestinationTableName = tableName;
await BulkCopy.WriteToServerAsync(reader);
}
}