Parallel.Invoke против выполнения задачи await / async - PullRequest
0 голосов
/ 03 апреля 2019

Наличие базового класса с двумя такими методами:

public void ReadAllData(List<Entity> entities){

        //processing
        foreach(Entity e in entities){
            ReadSingleData(entities[i]);
        }   
        //processing
}



  public void ReadSingleData(Entity entity){
        //processing
        db.ReadFromDataBase();
        //processing
    }

Мне нужно повысить скорость чтения из базы данных, заполнения коллекций и т. Д. Сначала я использовал эту реализацию с библиотекой Task Parallel:

Action[] actions = new Action[entities.Count);
public void ReadAllData(List<Entity> entities){

        //processing
        for(int i = 0; i< entities.Count;i++){
            actions[i] = new Action(() => ReadSingleData(entities[i]));
        }   
        //processing
}
ParallelOptions op = new ParallelOptions();
op.MaxDegreeOfParallelism = 6; //number of logical cores
Parallel.Invoke(op, actions);

И я использовал асинхронные / ожидающие методы:

Task<bool>[] tasks = new Task<bool>[entities.Count];
public void ReadAllData(List<Entity> entities){

        //processing
        for(int i = 0; i< entities.Count;i++){
            tasks[i] = ReadSingleData(entities[i]);
        }   
        Task.WaitAll(tasks);
        //processing
}

public async Task<bool> ReadSingleData(Entity entity){
    //processing
    await Task.Run(() =>
        db.ReadFromDataBase();
    });
    //processing
    return flag;
}

Это выше просто псевдокод.С выполнением задачи я получаю ускорение на 35-40% (около 30 секунд).Мой вопрос, как работает параллельная библиотека?Использует ли библиотека такие задачи, как моя вторая реализация?Что может быть не так с первой реализацией?Благодаря.

Ответы [ 2 ]

1 голос
/ 03 апреля 2019

Поскольку асинхронность в вашем втором подходе исходит от Task.Run(), они должны были выполнить более или менее то же самое. Я предполагаю, что entities.Count намного больше, чем 6. Обычно вам не нужно устанавливать MaxDegreeOfParallelism.

Но вы должны изучить правильную асинхронность, с db.ReadFromDataBaseAsync и без Task.Run ().

0 голосов
/ 03 апреля 2019

Разница в том, что Parallel.Invoke в некоторых случаях не порождает задачу для каждого запланированного на действие действия и ведет себя подобно Parallel.ForEach.Более подробно, если число задач больше, чем ваша степень параллелизма, которая либо явно указана (как в вашем случае), либо определена числом ядер, Parallel.Invoke разделяет действия, которые нужно вызывать в пакетах, чтобы соответствовать требуемой степенипараллелизма.Действия в одной партии выполняются последовательно.В отличие от этого Task.Run в подавляющем большинстве случаев планирует выполнение в пуле потоков.

В случае вычислений, ограниченных ЦП, логика Parallel.Invoke выигрывает, поскольку она подразумевает эффективное использование доступных ресурсов с небольшим количеством конфликтов.Связанные с вводом / выводом операции меняют ситуацию, так как теперь у вас много конфликтов ввода / вывода, которые могут остаться незамеченными в случае Parallel.Invoke и когда пропускная способность ввода / вывода не может быть полностью использована одновременными действиями Parallel.Invoke, число которых ограничено (другие операции, которые потенциально могут быть выполнены во время ввода-вывода, просто ожидают пакетами).Task.Run в таких сценариях имеет преимущество, потому что без верхнего предела параллелизма он может покрыть оставшуюся конкуренцию.Вот почему при определенных обстоятельствах это может увеличить производительность.Однако есть и обратная сторона: если приложение не контролируется, приложение Task.Run рискует привести к ситуациям, когда пул потоков перегружен задачами и должен порождать новые потоки для обслуживания входящих задач (когда количество запланированных задач ввода-вывода превышает I/ O), что, в свою очередь, может привести к снижению производительности.Вот почему рекомендуемый способ иметь дело с операциями, связанными с вводом / выводом, - это использовать async/await, поскольку он опирается на внутренние механизмы (например, порты завершения ввода / вывода), которые обеспечивают оптимальное использование ввода / вывода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...