【问题标题】:Run multiple actions in parallel in C#在 C# 中并行运行多个操作
【发布时间】:2019-05-25 06:47:54
【问题描述】:

我在 ASP.Net 网页表单页面中有以下代码,它基本上检查某个值是否在缓存中,如果没有,它会调用一个获取数据然后将其存储在缓存中的方法。获取数据的方法如下

ChartRenderingHelper.GenerateBidsStatusCreated(currYear.ToString(), currQuarter.ToString(), currYearType.ToString())

使用 EF 调用存储过程,这 3 个调用都调用单独的 SP。现在我按顺序执行,所以如果每个 SP 需要 5 秒,则总操作需要 15 ..我正在考虑使用一些任务来运行这些并行,但不知道如何更改我当前的代码来做到这一点。

  bidsCreated.Value = DashboardCacheHelper.IsIncache(bidsCreatedKey, useCaching) ? DashboardCacheHelper.GetFromCache(bidsCreatedKey) : (string)DashboardCacheHelper.SaveCache(bidsCreatedKey, JsonConvert.SerializeObject(ChartRenderingHelper.GenerateBidsStatusCreated(currYear.ToString(), currQuarter.ToString(), currYearType.ToString())), DateTime.Now.AddDays(cacheDays));
            bidsSubmitted.Value = DashboardCacheHelper.IsIncache(bidsSubmittedKey, useCaching) ? DashboardCacheHelper.GetFromCache(bidsSubmittedKey) : (string)DashboardCacheHelper.SaveCache(bidsSubmittedKey, JsonConvert.SerializeObject(ChartRenderingHelper.GenerateBidsStatusSubmitted(currYear.ToString(), currQuarter.ToString(), currYearType.ToString())), DateTime.Now.AddDays(cacheDays));
            bidsClosed.Value = DashboardCacheHelper.IsIncache(bidsClosedKey, useCaching) ? DashboardCacheHelper.GetFromCache(bidsClosedKey) : (string)DashboardCacheHelper.SaveCache(bidsClosedKey, JsonConvert.SerializeObject(ChartRenderingHelper.GenerateBidsStatusClosed(currYear.ToString(), currQuarter.ToString(), currYearType.ToString())), DateTime.Now.AddDays(cacheDays));

如何同时完成这 3 个作业?使用 TPL 我知道我们可以并行运行方法

Parallel.Invoke(() => DoSomeWork(), () => DoSomeOtherWork());

这是推荐的方法吗?如果我说 12 个操作需要并行运行,所有使用 EF 调用 SQL 存储过程都会是性能问题。

【问题讨论】:

  • 您可以使用Task.Run,然后使用Task.WaitAll
  • @SaniSinghHuttunen EF 有异步方法,所以你不需要Task.Run,OP 使用 ASP.Net 所以Task.WaitAll 会导致死锁 - 不完全确定你的建议是积极邪恶还是……没有深思熟虑?
  • 不要在 ASP.Net 页面中直接使用 Parallel,因为线程可能会在未完成工作的情况下被挂起,并且与 async 方法无法正常工作

标签: c# task-parallel-library .net-4.5


【解决方案1】:

您可以使用异步来实现这一点,但是最好有一个异步实现您的实体框架代码来添加和获取。

首先,我重构了代码以减少重复并通过引入方法GetOrAddAsync 使其更具可读性,该方法接受缓存键、useCaching 的布尔值(这是干什么用的?)和委托对于ChartRenderingHelper 方法。目前还不清楚currQuartercurrYearType 是什么类型。

private async Task<string> GetOrAddAsync(string cacheKey, bool useCaching, int cacheDays, DateTime currYear, ? currQuarter, ? currYearType, Action<string, string, string> cacheFactory)
{
    if(DashboardCacheHelper.IsIncache(cacheKey, useCaching))
    {
        return DashboardCacheHelper.GetFromCache(cacheKey);
    }

    return (string)(await DashboardCacheHelper.SaveCacheAsync(bidsClosedKey, JsonConvert.SerializeObject(cacheFactory(currYear.ToString(), currQuarter.ToString(), currYearType.ToString())), DateTime.Now.AddDays(cacheDays)).ConfigureAwait(false))
}

通过上面的方法,你的赋值代码就变成了

var bidsCreatedCacheTask = GetOrAddAsync(bidsCreatedKey, useCaching, cacheDays, currYear, currQuarter, currYearType, ChartRenderingHelper.GenerateBidsStatusCreated);
var bidsSubmittedCacheTask = GetOrAddAsync(bidsSubmittedKey, useCaching, cacheDays, currYear, currQuarter, currYearType, ChartRenderingHelper.GenerateBidsStatusSubmitted);
var bidsClosedCacheTask = GetOrAddAsync(bidsClosedKey, useCaching, cacheDays, currYear, currQuarter, currYearType, ChartRenderingHelper.GenerateBidsStatusClosed);

await Task.WhenAll(bidsCreatedCacheTask, bidsSubmittedCacheTask, bidsClosedCacheTask).ConfigureAwait(false);

bidsCreated.Value = await bidsCreatedCacheTask;
bidsSubmitted.Value = await bidsSubmittedCacheTask;
bidsClosed.Value = await bidsClosedCacheTask;

要记住的关键一件事是将您的调用方法标记为async,如果它是一个事件处理程序,那么它将是async void - 但请记住async void should otherwise be avoided 在任何不是'不是事件处理程序 - 因为您被限制为带有事件处理程序的 void 返回类型。

正如 LeBigCat 在 cmets 中指出的那样,ConfigureAwait 应与在 .NET Framework 上运行的异步代码一起使用以防止死锁,请阅读 here 了解原因。

【讨论】:

  • 我会添加 .configureAwait(false)。 OP 还需要确保他要写入缓存的数据是线程安全的。
  • 他正在使用网络表单页面
  • 我确实意识到,在我发布了该评论以及.net-4.5 标签之后。更新了代码。
  • 为了将它包含在我的 Page_Load 函数中,我已将其标记为异步......我希望没关系
  • 应该没问题,如果是事件处理程序则为async void,否则如果它有返回类型则为async Task&lt;T&gt;
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多