Мне нужно обрабатывать большое количество средних и больших файлов (от нескольких сотен МБ до ГБ) по-разному, поэтому меня интересуют стандартные подходы D для итерации по строкам. Идиома foreach(line; file.byLine())
, похоже, соответствует счету и является приятным и легким и понятным, однако производительность кажется менее идеальной.
Например, ниже представлены три тривиальные программы в Python и D для итерации по строкам файла и подсчета строк. Для файла ~ 470 МБ (~ 3.6M строк) я получаю следующие тайминги (лучше всего из 10):
D раз:
real 0m19.146s
user 0m18.932s
sys 0m0.190s
Время Python (после EDIT 2, см. ниже):
real 0m0.924s
user 0m0.792s
sys 0m0.129s
Здесь версия D, скомпилированная с помощью dmd -O -release -inline -m64
:
import std.stdio;
import std.string;
int main(string[] args)
{
if (args.length < 2) {
return 1;
}
auto infile = File(args[1]);
uint linect = 0;
foreach (line; infile.byLine())
linect += 1;
writeln("There are: ", linect, " lines.");
return 0;
}
И теперь соответствующая версия Python:
import sys
if __name__ == "__main__":
if (len(sys.argv) < 2):
sys.exit()
infile = open(sys.argv[1])
linect = 0
for line in infile:
linect += 1
print "There are %d lines" % linect
EDIT 2: я изменил код Python, чтобы использовать более идиоматический for line in infile
, как это предлагается в комментариях ниже, что приводит к еще большему ускорению для версии Python, которая сейчас приближается скорость стандартного вызова wc -l
для инструмента Unix wc
.
Любые советы или указатели на то, что я могу сделать неправильно в D, что дает такую плохую производительность?
EDIT. И для сравнения, здесь версия D, которая выкидывает идиому byLine()
из окна и сразу же всасывает все данные в память, а затем разбивает данные на строки post-hoc, Это дает лучшую производительность, но по-прежнему примерно вдвое медленнее, чем у Python.
import std.stdio;
import std.string;
import std.file;
int main(string[] args)
{
if (args.length < 2) {
return 1;
}
auto c = cast(string) read(args[1]);
auto l = splitLines(c);
writeln("There are ", l.length, " lines.");
return 0;
}
Тайминги для этой последней версии следующие:
real 0m3.201s
user 0m2.820s
sys 0m0.376s