Pull to refresh

Comments 80

Вы забыли самый быстрый стандартный способ:

while (std::getline(f, line))
{
    int x = std::stoi(line);
    max = std::max(x, max);
}
Спасибо за напоминание! Я в своё время рассматривал этот вариант, но не применил, потому что версия компилятора в университете была слишком старой. Сейчас обновлю пост.
У меня таким образом получается парсить в 2 раза быстрее, чем с помощью «boost::spirit::qi»…
Я бы с удовольствием посмотрел сравнение std::ostringstream с snprintf для форматирования строк.
А не отпугивает от потоков, кхм, некоторая многословность?
printf("%.2f\n", count * 100.0 / total);
vs
std::cout << std::setprecision(2) << std::fixed << count * 100.0 / total << std::endl
+ во времена g++ 3.3-4.0 в ostringstream была утечка памяти — с тех пор отношусь к ним с большой подозрительностью
В общем-то можно убрать std:: повсюду (добавив директиву ранее). Станет чуть короче.
Но вот со скоростью… мда…

Мы тут как-то свой printf делали (чтоб кидать дампы в обработчиках сигнала — где нежелательно, чтобы вдруг где-то malloc() в недрах вдруг вызвался, потому что будет «ой, всё!»). Структура то элементарна — очень простой ДКА — и уже можно по крайней мере целые числа и строки выводить.
Но вот добрались до флотов — и чтоб не городить огород попробовали самый простой метод, что на поверхности: вместо флота 1.99 — выводить целое 199, нарисовав точку после единицы (ну т.е. умножаем флот на precision, и выводим уже int, только в вывод впихиваем точку). Вот его как раз из любопытства забенчили по сравнению со стандартным printf.

Так вот такой бенч:
#ifdef USE_SPRINTF
void outf ( char* out, float arg )
{
	sprintf ( out, "%f", arg );
}
const char * sName = "Using sprintf res=%s\n";
#else
void outf ( char* out, float arg )
{
	unsigned int x = arg;
	arg -=x;
	UItoA ( &out, x);
	*out++='.';
	x=arg*1000000;
	UItoA ( &out, x);
	*out++='\0';
}
const char * sName = "Using own UItoA res=%s\n";
#endif

int main(int argc, char *argv[])
{
	float b;
	b=3556.2323;
	char cout[100];
	int i;
	for (i=0; i<100000000; ++i)
		outf(cout,b);
	printf (sName,cout);
	return 0;
}

(UItoA — это наша собственная очень простая реализация; не стал приводить. Но там в самом деле всё просто :) ).

А результат любопытный:
printf — 54.69c (при этом вывелось 3556.232422)
«целое с точкой» — 1.376с (при этом вывелось 3556.232421)

Разница — в 40 раз!
Т.е. если вдруг нужно выводить не хитрые флоты с огромными экспонентами, а вот такие, обычные, и причём нужно выводить много и быстро — свой «велосипед» рулит!
Реализация-то проприетарная?)
Могу посоветовать библиотеку stringencoders, в которой есть функции для преобразования чисел в строки:
code.google.com/p/stringencoders/wiki/PerformanceNumToA
code.google.com/p/stringencoders/wiki/NumToA

Работает значительно быстрее printf-семейства и лицензия MIT (на функции преобразования чисел в строки).
крутяк, а я то думаю, почему практически во всем коде по обработке данных в нашей лабе, юзают scanf для чтения, когда есть cin!

надо будет посмотреть как на кластере уменьшится время обработки данных (36гб .txt) если поменять всё на std::stoi
Не забудьте только выключить синхронизацию, если читаете из cin, иначе будет медленно. (Если читаете из файла, то отключать не нужно).
То есть при считывании из файла данная директива отключения синхронизации бесполезна и не даёт прироста скорости? Или же вообще вредна становится? Что произойдёт, если я всё же включу её перед считыванием данных из файла?
Синхронизация включена по умолчанию только на стандартных потоках: cin, cerr, cout, clog. На обычных файлах синхронизация и так должна быть выключена.
Что произойдёт, если я всё же включу её перед считыванием данных из файла?
Простите — но с чем именно вы собрались синхронизировать файловый поток? Для синхронизации требуется два объекта. cin синхронизирован с stdin, cout — с stdout, а с чем будет синхронизирован созданный вами объект?
Не знаю :)
Я только начинаю изучать плюсы и то, пока в рамках учебного курса в ВУЗе, поэтому многого ещё не понимаю. Но, будучи по натуре адовым перфекционистом, стараюсь искать все способы максимальной оптимизации.
Так а где же бенчмарк способа «читать данные большими кусками и дальше работать в памяти»?
походу, это std::istringstream + время на считывание
А как насчёт аналогичной замены getchar_unlocked() в Си на свою реализацию :)?
Что-нибудь вроде такого (я особо не оптимизировал, сорри):

#include <stdio.h>

long read_batched(long *out)
{
    char buf[20];
    long c, x = 0, neg = 0;
    char *res = fgets(buf, sizeof(buf), stdin);
    if (res == NULL) return 0;

    while ((c = *(res++)) != 0) {
        if ('0' <= c && c <= '9') {
            x = x*10 + c - '0';
        } else if (c == '-') {
            neg = 1;
        } else {
            break;
        }
    }

    *out = neg ? -x : x;
    return 1;
}

int main()
{
    long x;
    long max = -1;

    while (read_batched(&x)) {
	    if (x > max) max = x;
    }
    printf("%ld\n", max);
    return 0;
}
Или, лучше, вот такого:

#include <stdio.h>
#include <unistd.h>

int main()
{
    long max = -1;
    char buf[655360];
    long c, x = 0, neg = 0, n, i;

    while ((n = read(0, buf, sizeof(buf))) > 0) {
        for (i = 0; i < n; i++) {
            c = buf[i];
            if ('0' <= c && c <= '9') {
                x = (x<<1) + (x<<3) + c - '0';
            } else if (c == '-') {
                neg = 1;
            } else { // newline
                if (x > max) max = x;
                x = 0;
                neg = 0;
            }
        }
    }

    printf("%ld\n", max);
    return 0;
}
Ваш код — хороший пример того, что некоторые «классические» ручные оптимизации устарели, и только мешают компиляторам.

В вашем коде строка
x = (x<<1) + (x<<3) + c - '0';

компилируется в 3 инструкции lea:
	leaq	0(,%rbx,8), %rcx
	leaq	(%rcx,%rbx,2), %rcx
	leaq	-48(%rax,%rcx), %rbx

тогда как более наивное
x = x*10 + c - '0';

всего в 2 таких же инструкции
	leaq	(%rbx,%rbx,4), %rcx
	leaq	-48(%rax,%rcx,2), %rbx

Поиграться можно тут: gcc.godbolt.org
(Кстати, clang выдаёт второй вариант кода в обоих случаях)
Оптимизацию со сдвигом я просто взял из оригинальной функции freopen, которую вы «переписали» :)
Производительность, как и ожидалось, самая лучшая:
10M -> 0.16 с
100M -> 1.80 с
Только писать парсер чего-то более сложного — замучаться.
По-моему главная проблема iostreams не в скорости, а в очень спорном синтаксесе, который можно спутать с битовым сдвигом.
Спутать это может только тот, кто ни разу не работал с потоками. Все же обычно ввод-вывод используется как оператор (то есть результат операции никуда не сохраняется) — а битовый сдвиг используется внутри выражения.
Ну да, спутать конечно, врядли, я скорее про то, что это выглядит странно. Выводить и вводить данные уже определенным в языке оператором побитового сдвига. Притомерно так же, еслиб, например, у строк был переопределен оператор деления, для чего-нибудь.
А вас не смущает, что для строк переопределен оператор "+" — то есть математического суммирования? Думаю, что вы просто привыкли к этому и не задумываетесь. А вот в PHP, например (не к ночи будет помянут), насколько я помню, строки конкатенируются оператором "."…

Почему выбрали '<<' и '>>'? Я в головы авторам STL не заглядывал, но думаю, идеи такие:
Парсер C++ (в отличие от Perl, например), не дает возможности придумать какой-то свой, новый оператор. Применяется то, что есть.
Это с одной стороны. А с другой, сами операторы побитового сдвига применяются довольно редко, в основном только в контексте суровой целочисленной арифметики, которая очень редко соседствует в коде с работой ввода-вывода. Разумеется, я тут говорю о программах серьезных, а не о студенческих лабах. Кроме того, знак '<<' прямо просится, чтобы его прочесть как «пропихнуть влево» и даже человеку, незнакомому с возможностью переопределять операторы в C++, очень легко понять, что означает cout << "Hello!".

Что касается оператора деления для строк — а что, я бы, например, не прочь был посмотреть на split, который выглядит как stringList = "a,b,cc,ddd" / ','. Почему нет? Мы же делим строку на части, так? Отличная метафора…
Так дело решается наследованием и реализацией своего оператора. Если сами не хотите, могу сочинить пример)
Так Unix shell же, в нём запись в файл (поток) именно так и выглядит $ cmd >> file. Или это вам тоже кажется неудачным решением? Да и интуитивно это вполне понятно. Ведь оператор сдвига не просто так именно такой "<<" или ">>" воспринимается как перемещение чего-либо влево или вправо соответственно. Как уже говорилось выше, никто не считает, что "+" — неудачный оператор для конкетации строк, потому что он интуитивно понятен. Оператор >> в качестве оператора вывода тоже вполне понятен интуитивно и поэтому, как мне кажется, вполне удачен.
UFO just landed and posted this here
<< отлично подходят по приоритету (по сравнению с другими операциями которыйе могут быть в строчке) и по порядку вызова слева на право.
Можно было ещё читать с помощью getchar_unlocked в буфер типа char[12] (если в строке больше символов, это в int32 всё равно не влезет — игнорировать или сообщать об ошибке), а потом atoi сделать. Тогда можно не парсить цифры вручную, а скорость должна быть сравнимая с самым быстрым способом.
Если хотите совсем-совсем быстро, то когда-то давно уже проводили и обсуждали большие сравнения: (раз, два) как для ввода, так и для вывода, рекомендую!
Спасибо за ссылки! А набор способов у меня почти тот же самый.
Ещё нужно помнить про локали. У сишной и плюсовой частей они рулятся независимо, но об этом часто забывают.
Например, выводим через cout. А читаем через sscanf.
В рантайме плюсовая библиотека при запуске выставит локаль в системную. А сишная часть останется в C.
И банальный код, который запишет в файл float-значение через cout, а потом попытается прочитать его через sscanf окажется зависимым от системной локали! (например, запишется число с разделителем-запятой. А при чтении будет ожидаться точка -> ошибка!)
Действительно интересно — а влияет ли выбранная локаль?
std::locale loc(std::locale("C"));
std::cin.imbue(loc);

Правда следует иметь ввиду, что копирование локали почему-то довольно медленная операция.
Интересно было бы с node.js сравнить, например.
Сравните! Я вот, например, взял и померил для Java (ради интереса). Использовал самый тупой способ — класс Scanner, который является некоторым аналогом потока ввода из iostream. Получилась вот такая прога:
package readnum;

import java.util.Scanner;

public class ReadNum {
	public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		int max = 0;
		while (sc.hasNextInt()) {
			int next = sc.nextInt();
			if (next > max) {
				max = next;
			}
		}
		System.out.println("Max: " + max);
	}
}


И вот вывод ее:
$ time java -cp bin readnum.ReadNum < data
Max: 999999

real    0m2.173s
user    0m0.031s
sys     0m0.015s


Две с хвостиком секунды. Вполне достойно, как мне кажется. То есть с getchar не сравнить, но с iostream вполне конкурирует…
Это потому, что я — дурень и читал целые числа. А они закончились на 1 миллионе (который в файле отображен как 1e+6)

Так что беру свои слова назад. У меня — кошмар по производительности:

package readnum;

import java.util.Scanner;

public class ReadNum {
	public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		double max = 0;
		while (sc.hasNextDouble()) {
			double next = sc.nextDouble();
			if (next > max) {
				max = next;
			}
		}
		sc.close();
		System.out.println("Max: " + max);
	}
}


$ time java -cp bin readnum.ReadNum < data
Max: 1.0E7

real    1m2.414s
user    0m0.015s
sys     0m0.031s


Чтобы спасти положение, добавляем буфферизацию:

package readnum;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Scanner;

public class ReadNum {
	public static void main(String[] args) {
		
		Scanner sc = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
		double max = 0;
		while (sc.hasNextDouble()) {
			double next = sc.nextDouble();
			if (next > max) {
				max = next;
			}
		}
		sc.close();
		System.out.println("Max: " + max);
	}
}


получаем копеечный прирост:
$ time java -cp bin readnum.ReadNum < data
Max: 1.0E7

real    1m1.802s
user    0m0.015s
sys     0m0.015s


из чего делаем вывод — тормозит Scanner. Избавляемся от него:

package readnum;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class ReadNum {
	public static void main(String[] args) throws IOException {
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		double max = 0;
		String line;
		while ((line = br.readLine()) != null) {
			double next = Double.parseDouble(line);
			if (next > max) {
				max = next;
			}
		}
		br.close();
		System.out.println("Max: " + max);
	}
}


И получаем отличный результат:
$ time java -cp bin readnum.ReadNum < data
Max: 1.0E7

real    0m2.222s
user    0m0.000s
sys     0m0.047s


То есть те же 2 секунды, что и для iostream. Из чего делаем простой вывод: Java быстро читает и достойно парсит double. Но Scanner никуда не годится. Тормозит жутко. Если мне надо будет прочитать гигабайт чисел из потока ввода, воспользуюст вашим кодом с getchar и JNI. Слава богу, в реальности таких задач немного :)
UFO just landed and posted this here
cin из третьего варианта с 100 миллионами справился за 11.97 секунды, а следующая строчка на Haskell — за 6.87. Вот так вот.

import qualified Data.ByteString.Lazy.Char8 as B
import Data.Maybe
import Data.List

main = B.interact $ B.pack . show . foldl' max 0 . map (fst . fromJust . B.readInt) . B.lines
UFO just landed and posted this here
Data.Text работает с Unicode, что является непозволительной роскошью в данном случае. И вообще я удивлен, как оно вложилось в такое приличное время и не выжрало половину памяти с ленивым maximum.

Кстати, вариант с ByteString также обогнал 7 (getline + stoi) и 6a (getchar).
А мне кажется, что не совсем корректно приводить сравнение на максимальной оптимизации компилятора -O3. Всё же по умолчанию у gcc используется оптимизация -O2 — как более безопасная.
У GCC в -O3 нет ничего «небезопасного». Это какой-то старый миф (возможно, в каких-то старых версиях было по-другому).
-O3
Optimize yet more. -O3 turns on all optimizations specified by -O2 and also turns on the -finline-functions, -funswitch-loops, -fpredictive-commoning, -fgcse-after-reload, -ftree-loop-vectorize, -ftree-loop-distribute-patterns, -ftree-slp-vectorize, -fvect-cost-model, -ftree-partial-pre and -fipa-cp-clone options.

Другое дело, что, теоретически, оптимизации из O3 могут приводить в раздуванию кода или падению производительности, хотя я на практике такого не наблюдал.
Я сам всегда использую -O3.
К сожалению это не миф, так как ошибок неправильной работы программы на -O3 было значительное количество по сравнению с -O2…
Я лишь хотел сказать, что немного не верно сравнивать время и возможности работы ввода и вывода, когда компилятор ради увеличения времени компиляции сокращает и упрощает код, тем самым меняя изначальный контекст самого сравнения.
Скорее всего, ошибки таки в самой программе, а не в оптимизациях компилятора.
Компилятор — такая же программа, написанная программистами, допускающими ошибки.
Поверьте, не всегда правильно работают даже компиляторы.
как пример
Никто не отрицает. Но случаев когда в неправильной работе программы после оптимизации действительно виноват компилятор — единицы, против целого моря кривого кода кишащего UB.
Скорее всего, там ошибки в оптимизациях программы, а не в оптимизациях компилятора.
Очень занимательная статья, спасибо.

Вопрос к измерениям: времена получены на единичном запуске или это среднее по какому-то значению?
* по количеству запусков, конечно.
Я усреднял по 3-5 запускам. Но поскольку не ставилось задачи измерить точно, а только качественно сравнить, я не заморачивался с процедурой измерения.
Не подскажете, какой разброс был для коротких времен?
Для getchar_unlocked (первое измерение опущено):
0.271
0.276
0.278
0.272
0.282
То есть разброс около 0.01 с (поэтому времена приведены с 2 знаками).
iostreams — это не часть STL, это часть стандартной библиотеки.
А с чем связана такая низкая производительность с clang?
В основном виновата libc++. С чем это связано, не знаю, возможно libc++ оптимизирован в основном для MacOS, а оптимизации на Linux + GNU внимание не уделялось. При использовании libstdc++ производительность получается почти как у GCC (но все равно ниже).
А если попробовать mmap? Мне кажется это должно быть быстрее всего.
Только если у вас не btrfs.
UFO just landed and posted this here
UFO just landed and posted this here
Забавно, что лично у меня на моем процессоре быстрее всего работает такая программа (файл test.c):

#include <stdio.h>
#include <unistd.h>

int main()
{
    long max = -1;
    char buf[655361], *bufp;
    long c, x = 0, n;

    while ((n = read(0, buf, sizeof(buf) - 1)) > 0) {
        buf[n] = 0;
        bufp = buf;
        while ((c = *(bufp++)) != 0) {
            c -= '0';
            if (c >= 0 && c <= 9) {
                x = x*10 + c;
            } else if (c == '\n' - '0') {
                if (x > max) max = x;
                x = 0;
            }
        }
    }

    printf("%ld\n", max);
    return 0;
}


Если посмотреть на времена, то получается вот что:

$ clang -o merhalak -O3 merhalak.c
$ time ./merhalak <ololo.txt
warning: this program uses gets(), which is unsafe.
683641836811

real	0m1.166s
user	0m1.123s
sys	0m0.037s
$ clang -o test -O3 test.c
$ time ./test <ololo.txt
683641836811

real	0m0.145s
user	0m0.118s
sys	0m0.025s


Если компилировать с помощью gcc 4.9, то ваша программа становится чуточку быстрее, а моя — чуточку медленее:

$ gcc-4.9 -o merhalak -O3 merhalak.c && time ./merhalak <ololo.txt 
warning: this program uses gets(), which is unsafe.
683641836811

real	0m1.140s
user	0m1.104s
sys	0m0.033s

$ gcc-4.9 -o test -O3 test.c && time ./test <ololo.txt 
683641836811

real	0m0.166s
user	0m0.140s
sys	0m0.024s
UFO just landed and posted this here
Используйте fgets вместо get_s ;).
Про c++ и про c++11 в частности я ничего не знаю :). В любом случае, в clang поддержка C++ не очень хорошая
UFO just landed and posted this here
В стандарте безопасные функции (с окончанием _s ) описаны в приложении K как optional.
Так что википедия в данном случае неточна.
В clang поддержка C++ как раз считается одной из самых лучших. А с неподдержкой чего столкнулись вы столкнулись?
Я, к счастью, не пишу на C++, поэтому не сталкивался с тем, что в clang что-то не поддерживается. Но мое утверждение было основано на том, что поскольку clang спонсировался долгое время компанией Apple, то в первую очередь в clang развивалась поддержка C и Objective C, и во вторую очередь C++. Сейчас, возможно, ситуация меняется, но очень долгое время поддержка C++ в clang была не в приоритете.
threads.h в стандарте объявлен необязательным.

The headers <complex.h>, <stdatomic.h>, and <threads.h> are conditional features that implementations need not support; see 6.10.8.3.

Новые версии gcc и clang на Linux x86 поддерживают <threads.h> (ох уж этот хабрапарсер), хотя, вообще говоря, не обязательны для поддержки согласно стандарту. По очевидным причинам — в некоторых ОС потоков просто нет ) Так что уточните, пожалуйста платформу и ось
UFO just landed and posted this here
О, извините за невольное введение в заблуждение. Был невнимательным и подумал что речь идёт о C++. GCC до сих пор не поддерживает threading из c11, да и вообще много чего оттуда не поддерживает. Судя по всему, проблема не с компилятором а с библиотекой.
Кажется, что из одного заблуждения вывели, а в другое ввели. «много чего» это threading, analyzability и bounds-checking? В шапке ведь написано, что поддержка C11 практически полностью обеспечена с парой примечаний. А библиотека, то библиотека, со стороны компилятора всё необходимое реализовано.
результаты на linux mint 17.2,
clang 3.5.0-4, x84_64. $ seq 1000000 | time testN
Скрытый текст
scanf
10000000
1.35user 0.06system 0:01.52elapsed 92%CPU (0avgtext+0avgdata 2724maxresident)k
0inputs+0outputs (0major+116minor)pagefaults 0swaps
iostream + nosync
10000000
1.47user 0.04system 0:01.59elapsed 95%CPU (0avgtext+0avgdata 2620maxresident)k
0inputs+0outputs (0major+119minor)pagefaults 0swaps
iostream
10000000
4.27user 0.07system 0:04.40elapsed 98%CPU (0avgtext+0avgdata 2600maxresident)k
0inputs+0outputs (0major+112minor)pagefaults 0swaps
iostream + ss + nosync
10000000
6.73user 0.06system 0:06.86elapsed 99%CPU (0avgtext+0avgdata 2624maxresident)k
0inputs+0outputs (0major+119minor)pagefaults 0swaps
iostream + ss
10000000
11.05user 0.13system 0:11.33elapsed 98%CPU (0avgtext+0avgdata 2572maxresident)k
0inputs+0outputs (0major+112minor)pagefaults 0swaps
iostream + ss2 + nosync
10000000
2.42user 0.03system 0:02.49elapsed 98%CPU (0avgtext+0avgdata 2620maxresident)k
0inputs+0outputs (0major+117minor)pagefaults 0swaps
iostream + ss2
10000000
5.51user 0.08system 0:05.62elapsed 99%CPU (0avgtext+0avgdata 2572maxresident)k
0inputs+0outputs (0major+110minor)pagefaults 0swaps
getchar + nosync
10000000
1.05user 0.09system 0:01.18elapsed 96%CPU (0avgtext+0avgdata 2592maxresident)k
0inputs+0outputs (0major+117minor)pagefaults 0swaps
getchar
10000000
1.09user 0.06system 0:01.23elapsed 93%CPU (0avgtext+0avgdata 2536maxresident)k
0inputs+0outputs (0major+111minor)pagefaults 0swaps
getchar unl + nosync
10000000
0.64user 0.08system 0:00.74elapsed 98%CPU (0avgtext+0avgdata 2588maxresident)k
0inputs+0outputs (0major+114minor)pagefaults 0swaps
getchar unl
10000000
0.70user 0.06system 0:00.87elapsed 87%CPU (0avgtext+0avgdata 2536maxresident)k
0inputs+0outputs (0major+111minor)pagefaults 0swaps


вариант stoi не скомпилился
iostreams_performance.cpp:146:22: error: no member named 'stoi' in namespace 'std'
        int x = std::stoi(line);

а мне было лень исправлять

g++ 4.8.2
Скрытый текст
scanf
10000000
1.35user 0.06system 0:01.48elapsed 95%CPU (0avgtext+0avgdata 2664maxresident)k
168inputs+0outputs (1major+112minor)pagefaults 0swaps
iostream + nosync
10000000
1.47user 0.05system 0:01.58elapsed 96%CPU (0avgtext+0avgdata 2636maxresident)k
0inputs+0outputs (0major+122minor)pagefaults 0swaps
iostream
10000000
4.30user 0.07system 0:04.41elapsed 99%CPU (0avgtext+0avgdata 2540maxresident)k
0inputs+0outputs (0major+113minor)pagefaults 0swaps
iostream + ss + nosync
10000000
6.89user 0.07system 0:07.03elapsed 98%CPU (0avgtext+0avgdata 2564maxresident)k
0inputs+0outputs (0major+119minor)pagefaults 0swaps
iostream + ss
10000000
10.72user 0.09system 0:10.89elapsed 99%CPU (0avgtext+0avgdata 2544maxresident)k
0inputs+0outputs (0major+113minor)pagefaults 0swaps
iostream + ss2 + nosync
10000000
2.21user 0.04system 0:02.30elapsed 97%CPU (0avgtext+0avgdata 2636maxresident)k
0inputs+0outputs (0major+120minor)pagefaults 0swaps
iostream + ss2
10000000
5.37user 0.08system 0:05.50elapsed 99%CPU (0avgtext+0avgdata 2616maxresident)k
0inputs+0outputs (0major+115minor)pagefaults 0swaps
getchar + nosync
10000000
1.00user 0.06system 0:01.18elapsed 90%CPU (0avgtext+0avgdata 2640maxresident)k
0inputs+0outputs (0major+122minor)pagefaults 0swaps
getchar
10000000
0.94user 0.10system 0:01.15elapsed 90%CPU (0avgtext+0avgdata 2608maxresident)k
0inputs+0outputs (0major+113minor)pagefaults 0swaps
getchar unl + nosync
10000000
0.58user 0.08system 0:00.78elapsed 85%CPU (0avgtext+0avgdata 2636maxresident)k
0inputs+0outputs (0major+120minor)pagefaults 0swaps
getchar unl
10000000
0.58user 0.03system 0:00.64elapsed 97%CPU (0avgtext+0avgdata 2472maxresident)k
0inputs+0outputs (0major+109minor)pagefaults 0swaps
stoi + nosync
10000000
1.14user 0.02system 0:01.25elapsed 93%CPU (0avgtext+0avgdata 2636maxresident)k
0inputs+0outputs (0major+122minor)pagefaults 0swaps
stoi
10000000
4.09user 0.05system 0:04.25elapsed 97%CPU (0avgtext+0avgdata 2544maxresident)k
0inputs+0outputs (0major+113minor)pagefaults 0swaps

У меня с помощью getline+std::stod получается парсить в 2 раза быстрее, чем с помощью boost::spirit::qi… Конфигурация: MinGW 8.1 64 bit, C++17, boost 1.76. Файл содержит 2 миллиона триста тысяч строк, размер его — 365 мегабайт.

Вероятно, за прошелшие 7 лет stod немного оптимизировали. Я с тез пор эти тесты заново не проводил.

Sign up to leave a comment.

Articles