2014-11-15 3 views
2

Посмотрите на следующие четыре программы. Создавайте их с помощью Freepascal под Windows и запускайте, перенаправляя вывод в любой файл и замечая время, которое потребуется.Freepascal flush stdout на каждом выходе под Windows?

Мои результаты: все программы работают примерно в то же время (около 6 секунд), хотя четвертый делает в 100 раз больше байтов вывода. Это означает, что четвертая программа работает намного быстрее на каждый байт вывода, чем дерево других.

Для второй программы причина медлительности очевидна: вызов flush. Для третьей программы причина не так очевидна, но может быть разумно предположить, что каждый вызов writeln в stdout неявно очищает выходной буфер.

Однако непонятно, почему первая программа настолько медленнее, чем четвертая. Однако тот факт, что добавление flush(output); (см. Программу 2) не изменяет время, похоже, означает, что FPC сбрасывает выходной буфер даже после каждого write, это объясняет все поведение. Это происходит только тогда, когда вывод выводится на stdout, даже перенаправляется; если я явно выводю в конкретный файл с помощью функции assign/rewrite, то программа без флеша работает намного быстрее, чем программа с флешем - как и следовало ожидать.

Под Linux время работы 0,01, 0,65 с 0,01 с 0,30 (выход в 100 раз больше). Здесь явно flush() замедляет программу вниз, поэтому под Linux FPC, кажется, не сбрасывает stdout каждый раз.

Я попытался Google действительно ли промывает FPC стандартный вывод буфера на каждом выходе (будь то write или writeln), но не нашли никакой информации, кроме комментария в примере программы из промывочной функции документации на http://www.freepascal.org/docs-html/rtl/system/flush.html, комментарий упоминает о том, что writeln «Выход» всегда вызывает сброс [в отличие от write]. Тем не менее, пример там не дает предполагаемого вывода ни под Windows, ни под Linux. Фактически, вывод, кажется, покраснел после каждой записи и записи в Windows, перенаправлен или нет, и под Linux тоже, когда выход не перенаправлен. В Linux с перенаправленным выходом кажется, что никакого скрытого смывания вообще нет.

Итак, мои вопросы:

  1. Верно ли, что FPC очищает выходной буфер после каждого выхода, будь то write или writeln, на Windows, перенаправляется ли вывод в файл или нет?
  2. Если да, то есть ли способ отключить это (какая-либо директива компилятора или обходной путь)? Мне все равно нужно сохранить вывод в stdout, так что, если я запустил программу без каких-либо перенаправлений, она выведет текст на консоль. (Я понимаю, что я вижу, что он появляется в странные времена в результате буферизации, это не проблема.)
  3. Если нет, то почему первая программа работает намного медленнее, чем четвертая?

Моя система - Windows XP с FPC 2.6.4 под VirtualBox под Kubuntu 14.04 и сама Kubuntu 14.04 с FPC 2.6.2. У меня не было шансов запустить его на реальной машине Windows, но у меня есть некоторые причины полагать, что ситуация там же.


программы:

var i,j:integer; 
    s:string; 
begin 
for j:=1 to 1000 do begin 
    for i:=1 to 10 do 
     write('!'); 
end; 
end. 

var i,j:integer; 
    s:string; 
begin 
for j:=1 to 1000 do begin 
    for i:=1 to 10 do begin 
     write('!'); 
     flush(output); 
    end; 
end; 
end. 

var i,j:integer; 
    s:string; 
begin 
for j:=1 to 1000 do begin 
    for i:=1 to 10 do 
     writeln('!'); 
end; 
end. 

var i,j:integer; 
    s:string; 
begin 
for j:=1 to 10000 do begin 
    s:=''; 
    for i:=1 to 100 do 
     s:=s+'!'; 
    write(s); 
end; 
end. 
+0

1. это правда. Просто пример: 'writeln ('наберите это'); answer: = readln; 'if writeln не очистился, а конечный пользователь перед черной консолью. Это будет добавлено даже тогда, когда i/o не перенаправляется. –

+0

@ user3661500, я это понимаю и ожидал увидеть 'writeln', сбросив буфер, это то, о чем моя 3-я программа. Тем не менее, я был удивлен, увидев, что даже 'write' также очищает его. – Petr

ответ

7

Чтобы предотвратить Промывка STDOUT, вставьте следующие фрагменты кода в программе:

// Textrec is defined in sysutils 
uses 
    sysutils; 

// ... 

// disabled flushing after each write(ln) on Output, do this at the start of the program 
Textrec(Output).FlushFunc:=nil; 

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

Вы даже можете ускорить программу дополнительно путем увеличения выходного буфера на стандартный вывод:

// define buffer 
var 
    buf : array[1..100000] of byte; 

    // ... 

    // install buffer, do this at the start of the program 
    SetTextBuf(Output,buf,sizeof(buf)); 
+0

Трюк с FlushFunc очень интересный, спасибо! Попробуй это. – Petr

+0

Пробовал и может подтвердить, что он работает и решает мою проблему. – Petr