Параллельно с Entity Framework. Почему производительность впечатляет по сравнению с запуском нескольких исполняемых файлов? - PullRequest
9 голосов
/ 10 февраля 2012

Мне интересно, кто-нибудь из вас знает, почему мое выступление ужасно;

Чего я пытаюсь достичь; Создать 2,2 миллиона файлов. Для создания каждого файла требуется в среднем 2-5 вызовов базы данных.

Сервер, на котором я работаю, имеет 24 ядра и 190 ГБ ОЗУ.

Я разделил файлы, которые мне нужно сгенерировать, на 24 пакета.

Когда я использую следующий код, я получаю паршивую работу. Процесс генерации занимает более часа.

Parrallel.ForEach(batches, batch => 
{
    using (var ctx = new MyContext())
    {
        for each(var file in batch.Files)
        {
            GenerateFile(file);
        }
    }
});

Однако, когда я проверяю, что моя программа получает параметр, чтобы программа знала, какой пакет генерировать, мне не нужно использовать параллельную функциональность. Если я выполню программу для каждого пакета со следующим файлом .bat:

START CaMaakEiBericht.exe \B1
START CaMaakEiBericht.exe \B2
...
START CaMaakEiBericht.exe \B24

Он работает удивительно быстро! Общий процесс генерации занимает менее 15 минут! Этот пакетный файл также гарантирует, что каждое ядро ​​использует процессор примерно на 90%. Когда я использую параллельный подход, я получаю только 30-40% использования.

У кого-нибудь есть логическое объяснение этому? Я был доволен этим проектом, потому что у меня наконец появилась возможность использовать библиотеку .NET 4 Parallel в сочетании с EF, но, к сожалению, это меня как-то разочаровало: -)

У меня лично есть небольшое подозрение, что EF является узким местом здесь ... Кэширует ли он некоторые вещи внутри, что накладывает некоторые блокировки, когда несколько процессов извлекают данные?

Просвети меня: -)

1 Ответ

4 голосов
/ 10 февраля 2012

Я не могу сказать, почему ваш другой EXE-файл работает хорошо, но я могу предложить предложение для кода, который вы предоставляете.

Вы упомянули, что разбили свою работу на 24 пакета, а затем использовали ForEach над списком пакетов. При такой настройке может показаться, что каждое из наших 24 ядер может одновременно работать с одним файлом. Я думаю, это ваше узкое место.

Каждое ядро ​​может делать гораздо больше, если вы позволите. Попробуйте что-то вроде этого:

Parallel.ForEach(batches, batch => 
{
    Parallel.ForEach(batch.Files, file =>
    {
        using (var ctx = new MyContext())
        {
            GenerateFile(file);
        }     
    }
});

Или вы можете просто полностью избавиться от пакетов и предоставить им полный список файлов. Библиотека параллельных задач позаботится об использовании нескольких ядер для вас.

Parallel.ForEach(Files, file => 
{
    using (var ctx = new MyContext())
    {
        GenerateFile(file);
    }     
});

Вы, вероятно, уже знаете это, но имейте в виду, что контекст не является потокобезопасным , поэтому вам нужно создать новый внутри самой внутренней структуры Parallel.ForEach.

...