【问题标题】:Using Task.Run() for Linq - optimization or bottleneck将 Task.Run() 用于 Linq - 优化或瓶颈
【发布时间】:2016-10-15 22:37:38
【问题描述】:

我正在尝试优化一些旧项目,确保它们“一直异步”并且不会在较重的负载下崩溃。

我使用了以下 sn-p 的变体,但不确定 Task.Run 是优化还是可能的瓶颈。这种方法在一些较大的表单中得到了相当多的使用。

public static Task<List<SelectListItem>> ToMultipleSelectListItems<T>(this List<T> items, Func<T, string> nameSelector, Func<T, Guid> valueSelector, List<Guid> selected, Func<T, string> orderBy)
{
    Task<List<SelectListItem>> selectList = Task.Run(() => items.OrderBy(orderBy).Select(item =>
                    new SelectListItem
                    {
                        Text = nameSelector(item),
                        Value = valueSelector(item).ToString(),
                        Selected = selected.Contains(valueSelector(item))
                    }).ToList());
    return selectList;
}

示例调用..

model.Abilities = await (await Api.GetAbilities()).ToMultipleSelectListItems(
    x => x.Name, 
    x => x.Id, 
    model.Task.SelectedAbilitiesList, 
    x => x.OrderBy.ToString()
);

在我看来,当前线程在返回之前仍然需要等待新线程的响应。因此,在某些负载下,这可能会对 CPU 造成压力,甚至可能会最大化线程。我看不出有什么好处。

对于此场景中的最佳实践的任何反馈,我们将不胜感激。

【问题讨论】:

  • I fail to see an upside 那你为什么要这样做呢?除非您使用的是 winform 或 WPF 应用程序,并且您想从 UI 线程中卸载工作,否则在这里使用任务毫无意义
  • @KooKiz 我问的原因是因为我不确定是否将其遗漏会以某种方式阻碍“一直异步”,并可能会产生其他问题。有人看到了好处并首先写了这个,我想确保删除它是正确的。
  • @Mackan:这是 UI 还是 ASP.NET 项目?
  • @StephenCleary ASP.NET
  • 如果您考虑性能,您应该将List&lt;Guid&gt; selected 替换为HashSet&lt;Guid&gt; selectedselected.Contains(valueSelector(item) 将获得更好的性能。

标签: c# asp.net multithreading linq task


【解决方案1】:

没有任何好处。此代码将对可扩展性产生负面影响,并且根本没有任何好处。

有人看到了好处,首先写了这篇文章,

不,抱歉。

这只是一种效率较低的方法:

public static List<SelectListItem> ToMultipleSelectListItems<T>(this List<T> items, Func<T, string> nameSelector, Func<T, Guid> valueSelector, List<Guid> selected, Func<T, string> orderBy)
{
  return items.OrderBy(orderBy).Select(item =>
      new SelectListItem
      {
          Text = nameSelector(item),
          Value = valueSelector(item).ToString(),
          Selected = selected.Contains(valueSelector(item))
      }).ToList());
}

model.Abilities = (await Api.GetAbilities()).ToMultipleSelectListItems(
    x => x.Name, 
    x => x.Id, 
    model.Task.SelectedAbilitiesList, 
    x => x.OrderBy.ToString()
);

我们将不胜感激有关此场景中最佳实践的任何反馈。

以下是相关的最佳实践:“避免在 ASP.NET 上使用 Task.Run”。引用我的Intro to Async ASP.NET article

您可以通过等待 Task.Run 来启动一些后台工作,但这样做没有任何意义。事实上,这实际上会干扰 ASP.NET 线程池试探法,从而损害您的可伸缩性。如果您在 ASP.NET 上有 CPU 密集型工作要做,最好的办法是直接在请求线程上执行它。作为一般规则,不要将工作排队到 ASP.NET 上的线程池中。

【讨论】:

  • 好的,谢谢!我不确定开始的原因是因为我看到了一些关于“异步 linq”的 cmets,但我想在我的情况下这没什么好担心的,因为 API 调用首先等待并执行。
  • @Mackan:没错。我假设的GetAbilities 是一个真正的异步(基于EF6)查询,它应该是异步的。
  • 简洁,但异步是 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-03
  • 2017-05-08
  • 1970-01-01
  • 2011-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多