【问题标题】:Run variable number of LINQ queries asynchronously异步运行可变数量的 LINQ 查询
【发布时间】:2016-11-16 21:46:01
【问题描述】:

我想遍历一组 db 连接字符串并对所有数据库执行查询,然后将每个 IEnumberable 结果合并到一个 IEnumerable 列表中。同步版本如下所示:

public ActionResult ListSites()
{
    ConnectionStringSettingsCollection ConnectionStrings = ConfigurationManager.ConnectionStrings;

    List<SiteInfoModel> lstSites = new List<SiteInfoModel>();

    foreach (ConnectionStringSettings cn in ConnectionStrings)
    {
        lstSites.AddRange(getSitesForInstance(cn));
    }

    return View("~/Views/Sites/List.cshtml", lstSites);
}

private List<SiteInfoModel> getSitesForInstance(ConnectionStringSettings css)
{            
    using (STContext db = new STContext(css.ConnectionString))
    {
        IEnumerable<SiteTracker.Data.site_info> sites = db.Sites;

        return (from s in sites
                     orderby s.name
                     select new SiteInfoModel
                     {
                         instance = css.Name,
                         siteName = formatValue(s.name, s.active),
                         siteUrl = formatValue(s.url, s.active),
                         siteId = s.site_id,
                         isActive = s.active
                     }).ToList();                
    }
}

这个问题可能有几个子问题,因为我感觉我在为几个不同的事情苦苦挣扎:(1) getSitesForInstance() 应该如何编写?应该是

private async Task<List<SiteInfoModel>> getSitesForInstance()

如果它应该是异步的,那么我该如何编写 linq 表达式。我尝试将 IEnumerable 更改为 IQueryable 并使用 .ToListAsync() 但我收到有关投影非匿名类型的错误。是否可以在没有 async Task 的情况下编写它并且仍然让查询在所有连接字符串中同时执行?如果它可以通过任何一种方式完成,是更好还是更差。

问题的另一部分是 (2) ListSites() 在编写以进行并发数据库调用时应该如何看待?我看过this example,但它并没有让我找到一个可行的解决方案。我玩过这样的东西:

Task<List<SiteInfoModel>>[] tasks = new Task<List<SiteInfoModel>>[ConnectionStrings.Count];

for (int i = 0; i < ConnectionStrings.Count - 1; i++)
{
    tasks[i] = getSitesForInstance(ConnectionStrings[i]);
}
Task.WaitAll(tasks);

...但无法正常工作。每个数据库调用都返回一个列表。当所有任务的结果组合到变量 lstSites(即视图模型)中时,问题/问题就得到了解决/回答。

【问题讨论】:

  • 不知道为什么人们投票关闭 - 但我也不确定为什么它不起作用。您的异步版本到底有什么问题?我在一个运行良好的应用程序中做了类似的事情。

标签: c# asp.net-mvc linq asynchronous task-parallel-library


【解决方案1】:

这里有2个答案

要在 1 个变量中获得所有结果 - 您可以简单地使用 Parallel.ForEach https://stackoverflow.com/a/12610915/444149https://msdn.microsoft.com/en-us/library/dd460680(v=vs.110).aspx

谈到异步时.. 您需要做的第一件事是使您的方法GetSitesForInstance 异步。 这样做只是

  • 在方法名前添加 async 关键字
  • 在查询中使用 .ToListAsync()

第二次 调用方法时 - 在其前面添加“等待”。

【讨论】:

    【解决方案2】:

    下面是完成这项工作的代码:

    public async Task<ActionResult> ListAsync()
    {            
         ConnectionStringSettingsCollection ConnectionStrings = ConfigurationManager.ConnectionStrings;
    
         List<SiteInfoModel> lstSites = new List<SiteInfoModel>();
    
         Task<List<SiteInfoModel>>[] tasks = new Task<List<SiteInfoModel>>[ConnectionStrings.Count];
    
         for (int i = 0; i < ConnectionStrings.Count; i++)
         {
             tasks[i] = getSitesForInstanceAsync(ConnectionStrings[i]);
         }
    
         try
         {
             Task.WaitAll(tasks.ToArray());
         }
         catch (AggregateException) { }
    
         for (int ctr = 0; ctr < tasks.Length; ctr++)
         {
             if (tasks[ctr].Status == TaskStatus.Faulted)
                 Console.WriteLine("error occurred in {0}", ConnectionStrings[ctr].Name);
             else
             {
                 lstSites.AddRange(tasks[ctr].Result);
             }
    
         }
    
         return View("~/Views/Sites/List.cshtml", lstSites);
     }
    
    private Task<List<SiteInfoModel>> getSitesForInstanceAsync(ConnectionStringSettings css)
     {
         return Task.Run(() => getSitesForInstance(css));
     }
    

    Visual Studio 抱怨 ListAsync() 不使用 await 关键字,但它工作正常。这是一个问题吗?似乎 Task.WaitAll() 正在等待

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-30
      • 2018-11-06
      • 2011-12-03
      相关资源
      最近更新 更多