Производительность карты C++ - Linux (30 секунд) по сравнению с Windows (30 минут)!

Я должен обработать список файлов. Действие обработки не должно быть повторено для того же файла. Код, который я использую для этого, -

using namespace std;

vector<File*> gInputFileList; //Can contain duplicates, File has member sFilename
map<string, File*> gProcessedFileList; //Using map to avoid linear search costs

void processFile(File* pFile)
{
    File* pProcessedFile = gProcessedFileList[pFile->sFilename];
    if(pProcessedFile != NULL)
        return; //Already processed

    foo(pFile); //foo() is the action to do for each file
    gProcessedFileList[pFile->sFilename] = pFile;
}

void main()
{
    size_t n= gInputFileList.size(); //Using array syntax (iterator syntax also gives identical performance)
    for(size_t i=0; i<n; i++){
        processFile(gInputFileList[i]);
    }
}

Код работает правильно, но...

Моя проблема состоит в том, что, когда входной размер 1000, требуется 30 минут - ПОЛЧАСА - на Экспрессе Windows/Visual Studio 2008. Для того же входа требуется только 40 секунд для работы Linux/gcc!

Какова могла быть проблема? Нечто действия () занимает только очень короткое время для выполнения при отдельном использовании. Если я использую что-то как вектор:: зарезервировать для карты?

РЕДАКТИРОВАНИЕ, ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ

То, что делает нечто (): 1. это открывает файл 2. чтения это в память 3. закрывает файл 4. содержание файла в памяти анализируется 5. это создает список маркеров; я использую вектор для этого.

Каждый раз, когда я повреждаю программу (при запущении программы с 1000 + входной набор файлов): стек вызовов показывает, что программа посреди станд.:: вектор добавляет.

6
задан sonofdelphi 14 May 2010 в 10:14
поделиться

10 ответов

В Microsoft Visual Studio существует глобальная блокировка при доступе к стандартной библиотеке C ++ для защиты от проблем с многопоточностью в отладочных сборках. Это может привести к значительному снижению производительности. Например, наш полный тестовый код запускается в Linux / gcc за 50 минут, тогда как в Windows VC ++ 2008 ему требуется 5 часов. Обратите внимание, что этого снижения производительности не существует при компиляции в режиме выпуска с использованием среды выполнения Visual C ++ без отладки.

18
ответ дан 8 December 2019 в 03:09
поделиться

Я бы подошел к этому как к любой проблеме с производительностью. Это означает: профилирование . Между прочим, MSVC имеет встроенный профилировщик, так что это хороший шанс познакомиться с ним.

3
ответ дан 8 December 2019 в 03:09
поделиться

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

2
ответ дан 8 December 2019 в 03:09
поделиться

Я очень сильно сомневаюсь, что ваша проблема с производительностью исходит из контейнеров STL.

Попробуйте исключить (закомментировать) вызов foo (pFile) или любой другой метод, который затрагивает файловую систему. Хотя запуск foo (pFile) один раз может показаться быстрым, запуск его для 1000 различных файлов (особенно в файловых системах Windows, по моему опыту) может оказаться намного медленнее (например, из-за поведения кеша файловой системы)

РЕДАКТИРОВАТЬ

В вашем первоначальном сообщении утверждалось, что были затронуты ОБЕИХ сборок отладки и выпуска.Теперь вы отзываете это требование.

Имейте в виду, что в сборках DEBUG:

  1. реализация STL выполняет дополнительные проверки и утверждения
  2. куча операций (выделение памяти и т. Д.) выполняет дополнительные проверки и утверждения; кроме того, в отладочных сборках куча низкой фрагментации отключена (общее замедление памяти распределение)
  3. оптимизация кода не выполняется, что может привести к дальнейшему ухудшению производительности STL (STL часто сильно полагается на встраивание, раскручивание цикла и т. д.)

С 1000 итерациями вы, вероятно, не затронуты вышеизложенным (по крайней мере, на уровне внешнего цикла), если вы не используете STL / кучу в значительной степени INSIDE foo ().

2
ответ дан 8 December 2019 в 03:09
поделиться

Попробуйте прокомментировать каждый блок или основную операцию, чтобы определить, какая часть на самом деле вызвала разницу во времени выполнения в Linux и Windows. Я также не думаю, что это могло быть из-за карты STL. Проблема может быть внутри foo (). Это может быть в какой-то файловой операции, поскольку это единственное, о чем я мог подумать, что в данном случае будет стоить дорого.

Вы можете вставлять вызовы clock () между операциями, чтобы получить представление о времени выполнения.

1
ответ дан 8 December 2019 в 03:09
поделиться

Вы говорите, что когда вы ломаетесь, вы попадаете в vector :: add. У вас нет vector :: add в коде, который вы нам показали, поэтому я подозреваю, что он находится внутри функции foo . Не видя этого кода, будет сложно сказать, в чем дело.

Возможно, вы случайно создали алгоритм Shlemiel the Painter .

1
ответ дан 8 December 2019 в 03:09
поделиться

Если вы делаете большую часть своей работы в linux, то я настоятельно рекомендую вам всегда компилировать в release mode только в windows. Это значительно облегчает жизнь, особенно учитывая все головные боли, связанные с негибкой работой с библиотеками в windows.

0
ответ дан 8 December 2019 в 03:09
поделиться

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

Попробуйте сначала удалить дубликаты из вашего вектора , а затем обработать их все.

1
ответ дан 8 December 2019 в 03:09
поделиться

Я буду поражен, если проблемы с производительностью, которые вы наблюдаете, имеют хоть какое-то отношение к классу map. Выполнение 1000 поисков и 1000 вставок должно занимать время порядка микросекунд. Что делает foo()?

1
ответ дан 8 December 2019 в 03:09
поделиться

Можно несколько улучшить ситуацию, если отказаться от карты и вместо этого разделить вектор. Это подразумевает изменение порядка списка входных файлов. Это также означает, что вы должны найти способ быстро определить, был ли файл уже обработан, возможно, с помощью флага в классе File. Если можно переупорядочить список файлов и если вы можете хранить этот грязный флаг в объекте File, то вы можете повысить производительность с O(n log m) до O(n) для n общих файлов и m обработанных файлов.

#include <algorithm>
#include <functional>
// ...
vector<File*>::iterator end(partition(inputfiles.begin(), inputfiles.end(),
                                      not1(mem_fun(&File::is_processed))));
for_each(inputfiles.begin(), end, processFile);

Если вы не можете переупорядочить список файлов или не можете изменить объект File, то вы можете заменить map на vector и затенять каждый файл в списке входных файлов флагом во втором векторе с тем же индексом. Это будет стоить вам O(n) места, но даст вам O(1) проверки на грязное состояние.

vector<File*> processed(inputfiles.size(), 0);

for( vector<File*>::size_type i(0); i != inputfiles.size(); ++i ) {
    if( processed[i] != 0 ) return;  // O(1)
    // ...
    processed[i] = inputfiles[i];    // O(1)
}

Но будьте осторожны: Вы имеете дело с двумя разными указателями, указывающими на один и тот же адрес, и это касается каждой пары указателей в двух контейнерах. Убедитесь, что один и только один указатель владеет указателем.

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

1
ответ дан 8 December 2019 в 03:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: