Запускать несколько действий параллельно в C # - PullRequest
0 голосов
/ 20 марта 2019

У меня есть приведенный ниже код на странице веб-форм ASP.Net, который в основном проверяет, находится ли какое-либо значение в кэше, а если нет, то вызывает метод, который получает данные, а затем сохраняет их в кэше. Метод, который получает данные ниже

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

вызывает сохраненный процесс с использованием EF, и все эти три вызова вызывают отдельные 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 операций, которые должны выполняться параллельно, все вызовы хранимых в SQL Procs с использованием EF, это будет проблемой для производительности.

1 Ответ

5 голосов
/ 20 марта 2019

Вы можете использовать асинхронность для достижения этой цели, однако лучше всего иметь асинхронную реализацию кода Entity Framework для добавления и извлечения.

Во-первых, я реорганизовал код, чтобы уменьшить дублирование и сделать его более читабельным, введя метод GetOrAddAsync, этот метод принимает ключ кеша, логическое значение для useCaching (для чего это нужно?) И делегат для ChartRenderingHelper методов. Не сразу понятно, что типа currQuarter и currYearType.

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 в противном случае следует избегать в любом методе, который не является обработчиком событий - потому что вы ограничены типом возврата void с обработчиком событий.

Как указал LeBigCat в комментариях, ConfigureAwait следует использовать с асинхронным кодом, который выполняется в .NET Framework для предотвращения взаимных блокировок, прочитайте здесь , чтобы понять, почему.

...