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

Автор MikeMirzayanov, 14 лет назад, По-русски
Если вы пишите на С++, то регулярно бывает так, что ввод написанный через std::cin начинает тормозить из-за громоздких входных данных. Конечно правильнее в таких случаях сразу же писать чтение данных более эффективно - хотя бы с помощью функции scanf. Но если тестирующая система использует GNU C++ (проверял на MinGW 4.4.1, но думаю и на других версиях тоже будет работать), а переписывать программу не хочется, то можно катастрофически ускорить чтение всего одной строкой, размещенной в начале программы:  ios_base::sync_with_stdio( 0) .

На моем примере, где надо было найти сумму миллиона целых чисел, это ускорило программу в 4.5 раза, приблизив время работы к варианту со scanf. Пробовал запускать этот же тест на MS Visual C++ 9.0 - но не ускоряет.
  • Проголосовать: нравится
  • 0
  • Проголосовать: не нравится

14 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Затестил, риально работает!
также виден прирост скорости операций I/O на GNU C++3.4.2
14 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
наверное общеизвестный факт:
Если вы пишите на Java, то регулярно бывает так, что ввод написанный через Scanner начинает тормозить из-за громоздких входных данных. 
По старой привычке я автоматически набираю Scanner in = new Scanner (System.in); int n = in.nextInt(); Но по опыту уже знаю, что намного лучше обрабатывает входные данные StreamTokenizer, но строчка:
in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
 int nextInt() throws IOException
   {
      in.nextToken();
      return (int)in.nval;
   }
выглядит немного пугающе...

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

    Я тоже пишу на Java. Как раз для таких случаев у меня припасён переписанный Сканер (Извините, если отступы сбились)

    class Scanner{

    StreamTokenizer in;

    Scanner(InputStream stream){
    in = new StreamTokenizer(new InputStreamReader(stream));
    }

    void asserT(boolean e){
    if (!e){
    throw new Error();
    }
    }

    int nextInt(){
    try{
    in.nextToken();
    asserT(in.ttype == in.TT_NUMBER);
    asserT(in.nval == (int)in.nval);
    return (int) in.nval;
    }catch (Exception e) {
    throw new Error();
    }
    }
    }

    Ну и метод запуска программы

    void run(){
    in = new Scanner(System.in);
    out = new PrintWriter(System.out);
    try {
    solve();
    }finally{
    out.close();
    }
    }

    Никаких посторонних "шаманств" не надо. Ассерты установлены, чтобы программа не дай бог не получила WA или ещё что-нить при некорректном вводе вместо Crash.

12 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Может есть способ сделать ускорение потокового ввод-вывода в Visual Studio?
12 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
У меня не получилось можете пожалуйста написать простой пример кода?
  • 12 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится
    Во-первых: Пробовал запускать этот же тест на MS Visual C++ 9.0 - но не ускоряет.

    а вообще так по идее
    #include <iostream>
    using namespace std;
    int main()
    {
    ios_base::sync_with_stdio( 0);
    int n;
    for (;;)
    cin >> n;
    return 0;
    }

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

    some one doesn't say anything twice unless he has a good reason for it ;)

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

Сейчас при решении кодчифа ( http://www.codechef.com/MARCH12/problems/HDELIVER ) столкнулся с одной проблемой.. раньше не встречал.. Кто-нибудь в курсе почему происходит такая вещь?

Значится так: я всегда пишу код в своём шаблоне, где у меня есть также строка ios::sync_with_stdio(0); в самом начале main(). Я обычно считываю cin/cout и программа не захотела заходить по ТЛ... ну естественно в первую очередь написал scanf(), но как бы зачем это делать в тех местах, которые отработают раз 100... так что исправил только там, где много данных считывается. Засылаю, получаю рантайм (ошибка доступа). Вобщем выяснил, что что-то не так считывается. Задача зашла только когда либо закомментил ios::sync_with_stdio(0); либо когда все cin исправил на scanf(). То есть проблема именно в том, что не может быть написано одновременно ios::sync_with_stdio(0); и чередование в середине программы cin и scanf(). Причём мне почему-то кажется, что раньше я так делал и никаких проблем связанных с этим не возникало.

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

    Ну тут чётко написано: If the synchronization is turned off, the C++ standard streams are allowed to act independently. In this case using both C and C++ standard streams at the same time leads to undefined behavior.

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

    Кстати возможно, что до этого всё было норм, ибо я отправлял в MSVS (а в ней работает всё корректно), а тут gcc-4.3.2.

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

      Мелкософт обычно плевать хотели на все стандарты, а тем более на какую-то там ios_base::sync_with_stdio — видно они не заморачиваются и синхронизируют любой i/o, игнорируя Ваши флаги.

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

        Зачем так категорично :) Просто реализация от Microsoft зачастую в случае undefined behavior молча выбирает какой-нибудь из вариантов дальнейшего выполнения программы. Это вполне соответствует требованиям стандарта. Другое дело, что часто такое боком выходит.

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

          Значение флага ios_base::sync_with_stdio — это не undefined behavior, это вполне осмысленное поведение, которое ожидает программист, выставив этот флаг. Но Microsoft этот флаг просто игнорируют (им лень было это реализовывать).

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

            Я вел речь об одновременном использовании sync_with_stdio(false) и чередовании cin/scanf, когда говорил про UB. А о том, что в реализации от Dinkumware (это ведь, кстати, не Microsoft виноват :) ) этот флаг игнорируется, я не знал. Вот что написано у них на сайте: "In this implementation there is no need to call the iostream member function sync_with_stdio to ensure such synchronization, nor is there any performance benefit in disabling it". И дело тут, похоже, не в лени..

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

              UB при чередовании cin/scanf — есть очевидное следствие отсутствия синхронизации, что в свою очередь дает прирост производительности. То, что в реализации, используемой Microsoft, не реализован такой режим — вовсе не есть плюс.

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

                Я нигде и не говорил, что это плюс. Просто делать утверждения, что во всем виновата Microsoft, лень, etc, не подтверждая это фактами — легко. На деле же, обычно, причины каких-то "косяков" гораздо глубже.

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

                  Хм... то, что было предусмотрено проектировщиками языка, но не было реализовано — как это назвать? Если не лень, то чёткий экономический просчёт — зачем тратить деньги на какую-то там оптимизацию, если это и так можно продать?

                  Главное же как себя подать — можно вон гордо написать "In this implementation there is no need to call the iostream member function sync_with_stdio to ensure such synchronization", хотя слова "In this implementation" явно лишние — в стандарте чётко прописано поведение по-умолчанию.

                  Ну а оправдание типа "наш продукт такой гавёный не по нашей вине, а потому что мы покупаем для него такой-то кусок в другой фирме" звучит смешно. ;)

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

                  А есть бенчмарки, которые показывают сильно лучшую скорость у gcc при выключенном синке? Если это не так, то я бы назвал это плюсом библиотеки от MS

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

                  без синка — TL с синком — заходит за половину отведенного времени. Не редкость.

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

                  Я не говорю о разнице gcc с синком и без, я говорю о разнице gcc с выключенным синком и MSVS

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

                  Egor, пожалуйста:

                  1255624 — G++ c включенным синком (200 мс)

                  1255626 — G++ с выключенным синком (50 мс)

                  1255627 — MS C++ (230 мс)

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

    Причём мне почему-то кажется, что раньше я так делал и никаких проблем связанных с этим не возникало.

    Вам очень везло. :-) У меня как и ожидается из названия и описания метода даже следующая простая программа загибается на gcc 4.3 mingw:

    #include <cstdio>
    #include <iostream>
    using namespace std;
    
    int main() {
    	ios_base::sync_with_stdio(0);
    	int x, y;
    	cin >> x;
    	scanf("%d", &y);
    	cout << x << ' ' << y << endl;
    	return 0;
    }
    
  • »
    »
    12 лет назад, # ^ |
      Проголосовать: нравится +11 Проголосовать: не нравится

    А название функции ios::sync_with_stdio не намекает? :)

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

      :-D Ну да... даже не вдумывался, в одно время тупо запомнил и всё :)

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

In my case , it is not working . See 4082110 , it has been accepted WITH OUT using "ios_base::sync_with_stdio(0)" , but when i used it in 4082115 , i got TLE .

What is wrong here ?

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

In my case , it is not working . See 4082110, it has been accepted WITH OUT using "ios_base::sync_with_stdio(0)" , but when i used it in 4082115 , i got TLE .

What is wrong here ?

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

    Now your code WITH "ios_base::sync_with_studio(0)" gets Accepted 4083080.

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

      What's the difference between these two code? I haven't find any change. :(

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

        One of them has the line "ios_base::sync_with_studio(0)", but other doesn't.

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

        when U use cin cout & scanf printf together the c++ itself syncs theme with each other it means that if U cout 1 then printf 2 then cout 3 then printf 4 it handles the problem of different buffers & you'll face this output:1 2 3 4 but if U place that code in the beginning of your code U'll surely face 1 before 3 & 2 before 4 but U can face 1 3 2 4 ,1 2 3 4, 2 4 1 3 ... but this disables a check which slows the code so U shouldn't use scanf & printf when this check is disabled but disabling the check isn't some times effective enough & you should use scanf printf to make a code quicker but if U want to make the code the quickest U can read the output by getchar() it's the quickest way but having it's own problems which isn't sometimes a good idea.anyway it's on your own decision to choose which one.

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

But sometimes using scanf is not the fastest when reading too large input size.

We can use getchar() to read integer byte by byte to make the input much faster and avoid TLE.