Почему печать возвратной каретки значительно снижает скорость выполнения оператора printf в C - PullRequest
2 голосов
/ 13 февраля 2020

Следующий код выполняет и печатает оператор ~ 20 раз в секунду.

    while (1) {
        TX(port, "j1");
        usleep(30000);
        printf("\nPosition:\t%s",  (*RX(port)).data);
    }

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

    while (1) {
        TX(port, "j1");
        usleep(30000);
        printf("\rPosition:\t%s",  (*RX(port)).data);
    }

Он производит точный формат, который я хочу, но теперь я получаю распечатку только каждые ~ 6 секунд. Кто-нибудь может объяснить почему и предложить решение?

Ответы [ 2 ]

3 голосов
/ 13 февраля 2020

Во многих системах количество времени, необходимое для вывода M порций данных общим объемом N байтов, пропорционально некоторому кратному M и некоторому кратному N. Чтобы избежать ненужной траты времени на небольшие выходные операции, многие версии стандарта библиотека будет пытаться агрегировать порции данных для вывода, чтобы уменьшить количество задействованных порций. Отправка новой строки в stdout интерпретируется как подсказка о том, что система должна немедленно вывести все данные до этого, не дожидаясь появления новых данных, но это работает только в том случае, если в данных есть новые строки. Если отправка возвращается без перевода строки, может потребоваться использовать fflush(stdout). заставить систему отправлять данные, не дожидаясь большего.

0 голосов
/ 13 февраля 2020

Причина, по которой выходные данные не обновляются немедленно, вероятно, связана с проблемой буферизации:

  • stdout обычно является буферизованной строкой, когда направляется на терминал.
  • \n in первый l oop приводит к сбросу ожидаемого вывода на каждой итерации.
  • Размер буфера по умолчанию варьируется от одной системы к другой, типичные размеры составляют 512, 1024, 2048 и 4096 байт.
  • каждый вывод имеет около дюжины байтов и происходит каждые 30 миллисекунд или более: для получения 2 килобайт требуется около 6 секунд, в соответствии с буфером 2 КБ.
  • когда буфер заполнен, он сбрасывается за один шаг и терминал очень быстро отображает около 200 сэмплов, оставляя только последний для показа.
  • очистка вывода с fflush() или установка stdout как небуферизованного в начале программы решит эту проблему ( см. { ссылка }).
  • обратите внимание, однако, что более короткие выходные строки оставят завершающие символы из предыдущего вывода видимыми в en г терминальной линии. Вы должны вывести escape-последовательность \033[K, чтобы очистить конец строки, если терминал ее поддерживает (linux, а терминалы MacOS поддерживают, Windows 'может и не быть). Кроме того, вы можете добавить завершающие пробелы, чтобы попытаться стереть предыдущие символы, но это только частичное решение.

Вот модифицированный l oop:

    for (;;) {
        TX(port, "j1");
        usleep(30000);
        printf("\rPosition:\t%s     ",  (*RX(port)).data);
        fflush(stdout);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...