c#正确的并行模式.对于异步等待方法

本文关键字:异步 方法 等待 于异步 并行 模式 | 更新日期: 2023-09-27 18:08:28

我想听听关于这个方法的一些建议。这是一个好的模式,还是其他的表现更好?

    public async Task<PortfolioLoans> GetSampleOfPortfolioLoanNumbers(int count = 1)
    {
        var sqlConn = new SqlConnection(this.DataMineConnectionString);
        var pfLoans = new PortfolioLoans();
        var ts = new ThreadSafeList<PortfolioLoan>();
        try
        {
          await Task.Run(() => {
              Parallel.For(0, count, async i =>
              {
               var loans = await sqlConn.QueryAsync("dbo.spGetSampleApplicationIDs", Parameters.Empty, Query.Returns<PortfolioLoan>());
               ts.AddRange(loans);
              });
              pfLoans.Loans.AddRange(ts.Clone());
          });
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
        return pfLoans;
    }

c#正确的并行模式.对于异步等待方法

Parallel类在async/await之前被释放。NOT支持使用async in作为方法主体。当你使用async时,它创建了一个匿名的async void函数,因为它不能告诉你什么时候工作完成了,它在你开始的任务完成之前就完成了。使用async/await的一组更现代的类是TPL Dataflow。

其次sqlConn不是线程安全的,你不能在多个线程同时使用它。你必须为每个线程创建一个新的连接对象。

最后,我会把钱放在pfLoans.LoansList<T>或类似的东西,不是线程安全的。不能从多个线程调用不是为处理来自多个线程的调用而设计的函数。你必须锁定对AddRange的调用,或者用一个线程安全的类替换掉这个类。

稍微清理一下并添加线程安全:

   public async Task<PortfolioLoans> GetSampleOfPortfolioLoanNumbers(int count = 1)
   {
        var pfLoans;
        try
        {
           pfLoans = await Task.Run(async () => {
              var sqlConn = new SqlConnection(this.DataMineConnectionString);
              var pls = new Portfolioloans();
              for(var i=0; i<count; i++)
              {
                  var loans = await sqlConn.QueryAsync("dbo.spGetSampleApplicationIDs", Parameters.Empty, Query.Returns<PortfolioLoan>());
                  pls.Loans.AddRange(loans);
              }
             return pls;
      });
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.Message);
    }
    return pfLoans;
}

除非这些查询花费太长时间,否则我不知道是否会将它们放在并行中。

编辑:我错过了sqlConn.QueryAsync上的异步,如果担心阻塞,那么你甚至不需要一个任务,因为QueryAsync已经是异步的。

  public async Task<PortfolioLoans> GetSampleOfPortfolioLoanNumbers(int count = 1)
  {
    var pfLoans = new PortfolioLoan();
    try
    {
          var sqlConn = new SqlConnection(this.DataMineConnectionString);
          var pls = new Portfolioloans();
          for(var i=0; i<count; i++)
          {
              var loans = await sqlConn.QueryAsync("dbo.spGetSampleApplicationIDs", Parameters.Empty, Query.Returns<PortfolioLoan>());
              pfLoans.Loans.AddRange(loans);
          }
   }
   catch (Exception ex)
   {
      Debug.WriteLine(ex.Message);
   }
   return pfLoans;
}