Блог пользователя madkite

Автор madkite, 12 лет назад, По-русски

Тут стал вопрос производительности операций чтения/записи. Напомню, что в С++ есть замечательная функция-флаг ios_base::sync_with_stdio() с помощью которой можно отключить синхронизацию стандартных потоков C и С++, и тем самым повысить производительность. Замечательный компилятор от не менее замечательной фирмы Microsoft этот флаг тупо игнорирует. Т.к. я не директор Microsoft и даже не ответственный за выпуск Visual Studio — мне глубоко всё равно кто в этом виноват. Для меня главное — результат.

Простой тест показал:

1255626 — G++ с выключенным sync_with_stdio — 50 мс

1255624 — G++ c включенным sync_with_stdio — 200 мс

1255627 — MS C++ с проигнорированным sync_with_stdio — 230 мс

Но, т.к. на этом сайте GNU C++ используется через одно место, т.е. через Microsoft Windows, используя непонятный порт под названием MinGW, то мне стало интересно какова реальная ситуация. Я взял две одинаковые виртуальные машины, запущенные на одной и той же физической — одну с 32-хбитной Windows, другую с 32-хбитным Linux. Сгенерировал файл с 10 млн. рандомных чисел (около 100МБ, генерировал, между прочим, кодом из этого поста). Взял простой код, считывающий эти 10 млн. чисел. И вот скриншоты того, что получилось:

Windows/MSVS с проигнорированным sync_with_stdio ~15 с

Windows/MinGW c включенным sync_with_stdio ~14 с

Windows/MinGW c выключенным sync_with_stdio ~3 с

Linux/GCC c включенным sync_with_stdio ~8 с

Linux/GCC c выключенным sync_with_stdio <3 с

Т.о. в некоторых случаях можно добиться несколько кратного увеличения производительности простой сменой ОС и компилятора. Можете попробовать сами ;)

  • Проголосовать: нравится
  • 0
  • Проголосовать: не нравится

»
12 лет назад, # |
  Проголосовать: нравится +22 Проголосовать: не нравится

Уверены, что можно доверять тестам под виртуальной машиной в разных операционных системах? У меня есть сомнения по этому поводу, учитывая, что современные виртуальные машины весьма сложны и далеки от простого линейного "имитирования" машинного кода.

(Из этой же серии у меня вот под VMWare недавно получилось, что на языке D map работает якобы в 3 раза быстрее, чем в C++ — что выглядит весьма подозрительно)

  • »
    »
    12 лет назад, # ^ |
    Rev. 3   Проголосовать: нравится 0 Проголосовать: не нравится

    В целом уверен — оно использует аппаратную виртуализацию (AMD-V) и затраты на это минимальны. Можете убедится сами без виртуализации (хотя сейчас чуть ли не половина серверов виртуализирована, и я не уверен, что на всех контест-сайтах используются не виртуализированные сервера).

    А в том, что разные операционные системы и был прикол — разница между MinGW и оригинальным GCC значительна, т.к. сами операционные системы сильно отличаются.

    Ну а конкретные тесты map-а на языке D стоит проверить... Потому как, например, вот это решение на Java (1255811) почти в два раза быстрее решения на MS C++ (1255627), что тоже выглядит весьма подозрительно. ;)

»
12 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Какие результаты дает clang на линуксе на такой же виртуалке? Мне кажется, что от компилятора должно мало зависеть в таком тесте.

Какие результаты показывает stdio, если выполнять те же самые действия?

  • »
    »
    12 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    От компилятора может зависеть используемая реализация стандартной библиотеки C++, а от неё уже весь I/O, в т.ч. и ios_base::sync_with_stdio() — это можно увидеть на примере MS C++, где реализация стандартной библиотеки от Dinkumware игнорирует sync_with_stdio, и в итоге один и тот же код работает в 4-5 раз медленнее, нежели с использованием gcc.

    Компилирование clang-ом ничего не дает по той простой причине, что результирующий файл всё-равно зависит от libstdc++.so, т.е. используется та же самая gnu'шная реализация стандартной библиотеки C++, что и при компилировании gcc. Ситуацию может изменить использование clang вместе с новой libcxx, но последняя пока в разработке.

    scanf работает немного быстрее, нежели cin даже с выключенным синком — 1,9-2,0 секунды (на линуксе с gcc).

»
12 лет назад, # |
Rev. 2   Проголосовать: нравится +11 Проголосовать: не нравится

Кстати, есть ещё один способ ускорить ввод данных с iostreams. По умолчанию cout привязан к cin, что означает, что при каждой операции над cin вызывается cout.flush(). Это сделано, чтобы такой код работал нормально:

cout << "Enter your name: ";
cin >> name;

Чтобы такого не происходило, надо вызвать cin.tie(NULL);.

  • »
    »
    12 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    если ввод чередуется с выводом, то так делать нельзя, верно?

    • »
      »
      »
      12 лет назад, # ^ |
      Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

      Так делать нельзя только на интерактивных задачах, где нужно вывести строку обязательно перед вводом новой (ну или надо использовать endl/flush явно). В остальных случаях хоть как чередуй, ничего плохого не будет — всё равно при закрытии файла весь буфер cout будет сброшен.