【问题标题】:Async for Bulk copy批量复制的异步
【发布时间】:2016-08-04 20:42:46
【问题描述】:

我有很多数据表要批量插入到数据库表中 由于尺寸较大,一张表需要 5 分钟才能完成插入。 2张桌子花了我10分钟

static void Main(string[] args)
{
    DataTableBulkInsert(DataTable1);
    DataTableBulkInsert(DataTable2);
}

public static void DataTableBulkInsert(DataTable Table){
    SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(myConnection);
    sqlBulkCopy.DestinationTableName = "dbo.DatabaseTable";
    myConnection.Open();                    
    sqlBulkCopy.WriteToServer(Table);
    myConnection.Close();
}

我现在正在尝试为批量插入执行异步操作,但既没有插入任何数据也没有给我错误。如何捕获异常?

static void Main(string[] args)
{
     var insert1 = Task.Run(async () => await DataTableBulkInsert(DataTable1);
     var insert2 = Task.Run(async () => await DataTableBulkInsert(DataTable2);
     Task.WhenAll( insert1, insert 2);
}

public static async Task<Boolean> DataTableBulkInsert(DataTable Table)
{
      try
      {
          SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(myConnection);
          sqlBulkCopy.DestinationTableName = "dbo.DatabaseTable";
          myConnection.Open();                    
          await sqlBulkCopy.WriteToServerAsync(Table);
          myConnection.Close();
      }
      catch (Exception (e))
      {
        console.write(e);
      }
      return true;
 }

【问题讨论】:

  • 你试过在console.write(e);线上设置调试器吗?根据我的经验,异步方法通常会吞下异常。
  • 使用Task.WaitAll(insert1, insert 2)

标签: c# asynchronous sqlbulkcopy


【解决方案1】:

Task.Runs 在这里没有添加任何有用的内容。此外,不要尝试在您的方法的两次运行之间共享单个连接object。比如:

static void Main(string[] args)
{
     var insert1 = DataTableBulkInsert(DataTable1);
     var insert2 = DataTableBulkInsert(DataTable2);
     Task.WaitAll( insert1, insert2);
}

public static async Task DataTableBulkInsert(DataTable Table)
{
      using(var localConnection = new SqlConnection(/* connection string */))
      {
          SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(localConnection );
          sqlBulkCopy.DestinationTableName = "dbo.DatabaseTable";
          localConnection.Open();                    
          await sqlBulkCopy.WriteToServerAsync(Table);
      }
 }

通常return await 是一种反模式,但在这里您要使用它,以便在批量加载完成之前using 语句不会关闭您的连接。

另外,我改用 Task.WaitAll,它实际上 等待,这比使用 Task.WhenAll 然后立即调用 Wait 更惯用。

【讨论】:

  • return await 是一种反模式 - 非常有趣。您能否提供更多有关这方面的信息?
  • @smoksnes - await 是一种暂停当前方法的方法,直到其他代码完成其工作。如果你的方法在恢复时要做的就是说“我完成了”,那么你为什么要全力以赴?话虽这么说,实际的反模式是return await,如果这是方法中的only await(因为它在这里)并且它不在带有finallytry 块内或using 块(在这种情况下,return 之后还有其他代码要运行)
  • @smoksnes - 甚至还有 github issue 要求编译器对其进行优化。
  • 感谢您的解释。
  • 当你的任务没有对象表达式时,我还需要返回吗?我有这个错误任务没有返回的对象表达式错误
【解决方案2】:

Task.WhenAll返回一个Task对象,需要等待或者后面的代码继续正常执行,main方法立即退出。

由于这是一个控制台应用程序,main不能标记为async,你可以使用这个:

Task.WhenAll(insert1, insert2).Wait(); // wait for the returned Task object to Complete

正常用法是:await (Task.WhenAll(...)),但不能将 Main 标记为 async 方法。

【讨论】:

  • 在我添加 .Wait();但是,现在我遇到了连接打开和关闭问题。如何让一个连接满足多个批量复制?
  • @Jonathan 您可能需要为每个任务创建单独的连接。或在Task.WhenAll(insert1, insert2).Wait(); 代码行之后关闭连接。
猜你喜欢
  • 2012-11-09
  • 2021-09-09
  • 2020-05-22
  • 2017-11-17
  • 1970-01-01
  • 1970-01-01
  • 2012-03-10
  • 2012-11-22
  • 2022-08-12
相关资源
最近更新 更多