Страницы

Поиск по вопросам

воскресенье, 26 января 2020 г.

Быстродействие считывания

#delphi #benchmark #cpp


Вообщем написаны 2 программы на Delphi и на C++ , провожу абсолютно однотипные операции(
считываю массив длинною 10 ^ 7) но почему то Delphi это делает на целую секунду быстрее,
кто может ответить в чем причина? и как можно ускорить в C++ ввод и вывод данных??


Вот программы, на Си и на Delphi

#include 
#include 

int n;
short a[10000000];

int main()
{
    freopen("output.txt", "r", stdin);
    freopen("input.txt", "w", stdout);

    scanf("%d\n", &n);
    for (int i = 0; i < n; i++)
        scanf("%hd", &a[i]);   
    printf("1");

    return 0;   
}




var n, i : integer;
      a : array[1..10000000] of shortInt;

begin
    reset(input, 'output.txt');
    rewrite(output, 'input.txt');

    ReadLn(n);
    for i := 1 to n do
      Read(a[i]);
    WriteLn('1');

    close(input);
    close(output);
end.  


Испытание 2.
  теперь первым выполняется exe - шник на c++ и в дельфи for заменен на while! все
остальное то же.



    var n, i : integer;
      a : array[1..10000000] of Integer;

begin
    reset(input, 'output.txt');
    rewrite(output, 'input.txt');

    ReadLn(n);
    i := 1;
    while ( i <= n ) do
    begin
      Read(a[i]);
      inc(i);
    end;
    WriteLn('1');

    close(input);
    close(output);
end.

    


Ответы

Ответ 1



Все очень просто. В случае с делфи, компилятор знает, что вызов Read будет читать число. И только его. И может вставить правильный код сразу. В случае с scanf ситуация не столь проста. Как минимум каждый раз будет делаться парсинг строки формата. А это как не оптимизируй - медленно. Что же делать? писать свой парсер. Но как то не то. использовать готовые парсеры, например boost.spririt также, по ссылкам ниже, народ пишет, что если читать строку, а потом преобразовывать с помощью atoi, то получается в 4 раза быстрее. полезные ссылки Снова про ввод/вывод в C++ scanf не предназначен для ввода большого кол-ва информации sprintf/sscanf и скорость - понятия совместимые ? рассуждают о том же

Ответ 2



Хотите быстро? Тогда забудьте об "удобных" функциях во внутреннем цикле. Вот, например #include #include #include #include #include #include #define fatal(msg) ({fprintf(stderr,"%s: %m",(msg)); exit(-1);}) int n; short a[10000000]; int main (int ac, char *av[]) { int in = open ("output.txt", O_RDONLY); if (in == -1) fatal("open output.txt"); // freopen("input.txt", "w", stdout); struct stat st; fstat (in,&st); printf ("len = %ld\n",(long)st.st_size); char *file = (char *)mmap(NULL,st.st_size,PROT_READ,MAP_PRIVATE,in,0), *p; if (!file) fatal("mmap"); madvise(p,st.st_size,MADV_SEQUENTIAL); n = strtol(file,&p,10); printf ("n = %d\n",n); int i; for (i = 0; i < n; i++) { while (*p <= ' ') p++; a[i] = 0; while (*p >= '0') a[i] = a[i]*10 + (*p++ - '0'); } printf ("i = %d, a[%d] = %d\n",i,i-1,a[i-1]); exit(0); } avp@avp-xub11:~/hashcode$ gcc -O3 mapio.c -o mapio avp@avp-xub11:~/hashcode$ tail -5 output.txt 9999995 9999996 9999997 9999998 9999999 avp@avp-xub11:~/hashcode$ cat input.txt 1 -27009 avp@avp-xub11:~/hashcode$ time ./mapio len = 78888899 n = 10000000 i = 10000000, a[9999999] = -27009 real 0m0.478s user 0m0.180s sys 0m0.228s avp@avp-xub11:~/hashcode$ tail показывает конец входного файла, а в Вашу программу я вставил печать последнего элемента a[], введенного scanf(), чтобы убедиться в результате своей программки. Сейчас попробую просто прочесть весь файл read-ом вместо mmap-а. Дополнение Код меняем так #if 0 char *file = (char *)mmap(NULL,st.st_size,PROT_READ,MAP_PRIVATE,in,0), *p; if (!file) fatal("mmap"); madvise(p,st.st_size,MADV_SEQUENTIAL); #else char *file = malloc(st.st_size), *p; if (read (in,file,st.st_size) != st.st_size) fatal("read"); #endif Получаем avp@avp-xub11:~/hashcode$ gcc -O3 mapio.c -o mapio avp@avp-xub11:~/hashcode$ time ./mapio len = 78888899 n = 10000000 i = 10000000, a[9999999] = -27009 real 0m0.989s user 0m0.144s sys 0m0.728s avp@avp-xub11:~/hashcode$

Ответ 3



Подозреваю что си код scanf("%hd", &a[i]); делает больше чем паскаль код Read(a[i]); Думаю как минимум на разбор входной строки.

Ответ 4



На StackOverflow есть совершенно замечательный (по объёму проведённой работы) вопрос на похожую тему: Why is reading lines from stdin much slower in C++ than Python? Основная идея там в том, что cin и stdio в С++ по умолчанию синхронизированы и из-за этого отключается буферизация. Надо делать cin.sync_with_stdio(false); Подробно про это - там, в первом ответе. Попробуйте.

Ответ 5



Профилирование программ, тем более на разных языках - почти искусство:) Однако - необходимость. Когда-то (10 лет назад) тестировал компиляторы на разных тестах: Один из видов тестов

Комментариев нет:

Отправить комментарий