Асинхронное сохранение в несколько таблиц на одном SQL сервере базы данных - PullRequest
0 голосов
/ 29 января 2020

Мне удалось параллельно заполнить несколько таблиц базы данных, используя Task.WhenAll (задачи). У меня есть метод generic c для каждой таблицы:

var tasks = new List<Task>()
        {
            CheckNewItems<S, T>(async () => await GetPrimaryKeys<S, T>(),
            CheckNewItems<S, T>(async () => await GetPrimaryKeys<S, T>(),
            CheckNewItems<S, T>(async () => await GetPrimaryKeys<S,T>(),                                                                     
            CheckNewItems<S, T>(async () => await GetPrimaryKeys<S,T>()
        };

        await Task.WhenAll(tasks);

Теперь появилось новое требование, в котором содержится просьба сохранить количество новых элементов из этого асинхронного c метода, и я наткнулся на этот пост. Я попытался сделать это так, как указано в комментариях к принятому ответу, чтобы получить количество новых элементов:

   int newItems = 0;
   newItems += await CheckNewItems<S, T>(async () => await GetPrimaryKeys<S, T>();
   newItems += await CheckNewItems<S, T>(async () => await GetPrimaryKeys<S, T>();
   newItems += await CheckNewItems<S, T>(async () => await GetPrimaryKeys<S,T>();                                                                     
   newItems += await CheckNewItems<S, T>(async () => await GetPrimaryKeys<S,T>();

Используя второй метод, таблицы базы данных обновляются не параллельно, а синхронно.

Внутри этого метода CheckNewItem я использую методы SaveChangesAsyn c и AddRangeAsyn c в EF Core. Я не уверен, почему использование Task.WhenAll (tasks) выполняет желаемое действие, а второй способ - нет, когда в post в некоторых комментариях упоминается, что вам не нужно выполнять Task .WallAll, чтобы убедиться, что асин c методы работают параллельно.

Я хотел бы получать результаты каждого вызова CheckNewItems, хотя они все еще могут сохраняться в базе данных асинхронно и параллельно, как обычно. Заранее благодарим за понимание и помощь:)

Ответы [ 3 ]

1 голос
/ 29 января 2020

Как насчет:

var tasks = new List<Task>()
        {
            CheckNewItems<S, T>(async () => await GetPrimaryKeys<S, T>(),
            CheckNewItems<S, T>(async () => await GetPrimaryKeys<S, T>(),
            CheckNewItems<S, T>(async () => await GetPrimaryKeys<S,T>(),                                                                     
            CheckNewItems<S, T>(async () => await GetPrimaryKeys<S,T>()
        };

await Task.WhenAll(tasks);
int newItems = 0;
foreach(var task in tasks){
     newItems+= await task;
}
0 голосов
/ 29 января 2020

Я не знаю, почему это работает так, как нужно:

        var task1 = CheckNewItems<S, T>(async () => await GetPrimaryKeys<S, T>();
        var task2 = CheckNewItems<S, T>(async () => await GetPrimaryKeys<S, T>();
        var task3 = CheckNewItems<S, T>(async () => await GetPrimaryKeys<S,T>();                                                                     
        var task4 = CheckNewItems<S, T>(async () => await GetPrimaryKeys<S,T>();

        newItems += await task1;
        newItems += await task2;
        newItems += await task3;
        newItems += await task4;

А это не так:

  newItems += await CheckNewItems<S, T>(async () => await GetPrimaryKeys<S, T>();
  newItems += await CheckNewItems<S, T>(async () => await GetPrimaryKeys<S, T>();
  newItems += await CheckNewItems<S, T>(async () => await GetPrimaryKeys<S,T>();                                                                     
  newItems += await CheckNewItems<S, T>(async () => await GetPrimaryKeys<S,T>();

В любом случае, я был бы очень признателен всем, кто может объяснить, почему. Я думаю, что мне нужно больше узнать о TPL.

0 голосов
/ 29 января 2020

await выполняет то, что говорит, ожидает завершения асинхронной задачи, прежде чем продолжить выполнение метода, с другой стороны, Task.WhenAll выполняет каждую задачу параллельно и возвращает ее после завершения последней.

Параллельно добавлять вещи не совсем просто, потому что для этого требуется операция atomi c. К счастью, это довольно просто с API, такими как Interlocked.Add ().

https://www.dotnetperls.com/interlocked

Редактировать: ответ Кристяна намного проще, так как вы будете добавлять счетчик после каждой задачи, просто используйте Task.Result вместо ожидания в foreach l oop, потому что нет необходимости ждать уже выполненную задачу только для того, чтобы получить ее значение (ожидание задачи - довольно дорогая операция)

...