Это действительно не должно иметь значения.
Если вы читаете с реального жесткого диска, это будет медленно. Жесткий диск - твоя горлышко от бутылки, и все.
Теперь, если вы глупы из-за вызова read / fread / что угодно и, скажем, fread () - байт за раз, тогда да, это будет медленно, как издержки fread ( ) превысит затраты на чтение с диска.
Если вы вызываете read / fread / what и запрашиваете приличную часть данных. Это будет зависеть от того, что вы делаете: иногда все, что вам нужно / нужно, - это 4 байта (чтобы получить uint32), но иногда вы можете читать большими кусками (4 КиБ, 64 КиБ и т. Д.). .)
Если вы выполняете небольшое чтение, некоторые вызовы более высокого уровня, такие как fread (), действительно помогут вам, буферизируя данные за вашей спиной. Если вы выполняете большие операции чтения, это может оказаться бесполезным, но переход с режима чтения на fread, вероятно, не приведет к такому улучшению, поскольку вы ограничены в скорости диска.
Короче говоря: если можете, попросите либеральную сумму при чтении и постарайтесь свести к минимуму то, что вы пишете. В больших количествах степени 2, как правило, более дружелюбны, чем что-либо еще, но, конечно, это зависит от операционной системы, аппаратного обеспечения и погоды.
Итак, давайте посмотрим, может ли это выявить какие-либо различия:
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#define BUFFER_SIZE (1 * 1024 * 1024)
#define ITERATIONS (10 * 1024)
double now()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec + tv.tv_usec / 1000000.;
}
int main()
{
unsigned char buffer[BUFFER_SIZE]; // 1 MiB buffer
double end_time;
double total_time;
int i, x, y;
double start_time = now();
#ifdef USE_FREAD
FILE *fp;
fp = fopen("/dev/zero", "rb");
for(i = 0; i < ITERATIONS; ++i)
{
fread(buffer, BUFFER_SIZE, 1, fp);
for(x = 0; x < BUFFER_SIZE; x += 1024)
{
y += buffer[x];
}
}
fclose(fp);
#elif USE_MMAP
unsigned char *mmdata;
int fd = open("/dev/zero", O_RDONLY);
for(i = 0; i < ITERATIONS; ++i)
{
mmdata = mmap(NULL, BUFFER_SIZE, PROT_READ, MAP_PRIVATE, fd, i * BUFFER_SIZE);
// But if we don't touch it, it won't be read...
// I happen to know I have 4 KiB pages, YMMV
for(x = 0; x < BUFFER_SIZE; x += 1024)
{
y += mmdata[x];
}
munmap(mmdata, BUFFER_SIZE);
}
close(fd);
#else
int fd;
fd = open("/dev/zero", O_RDONLY);
for(i = 0; i < ITERATIONS; ++i)
{
read(fd, buffer, BUFFER_SIZE);
for(x = 0; x < BUFFER_SIZE; x += 1024)
{
y += buffer[x];
}
}
close(fd);
#endif
end_time = now();
total_time = end_time - start_time;
printf("It took %f seconds to read 10 GiB. That's %f MiB/s.\n", total_time, ITERATIONS / total_time);
return 0;
}
... Выходы:
$ gcc -o reading reading.c
$ ./reading ; ./reading ; ./reading
It took 1.141995 seconds to read 10 GiB. That's 8966.764671 MiB/s.
It took 1.131412 seconds to read 10 GiB. That's 9050.637376 MiB/s.
It took 1.132440 seconds to read 10 GiB. That's 9042.420953 MiB/s.
$ gcc -o reading reading.c -DUSE_FREAD
$ ./reading ; ./reading ; ./reading
It took 1.134837 seconds to read 10 GiB. That's 9023.322991 MiB/s.
It took 1.128971 seconds to read 10 GiB. That's 9070.207522 MiB/s.
It took 1.136845 seconds to read 10 GiB. That's 9007.383586 MiB/s.
$ gcc -o reading reading.c -DUSE_MMAP
$ ./reading ; ./reading ; ./reading
It took 2.037207 seconds to read 10 GiB. That's 5026.489386 MiB/s.
It took 2.037060 seconds to read 10 GiB. That's 5026.852369 MiB/s.
It took 2.031698 seconds to read 10 GiB. That's 5040.119180 MiB/s.
... или нет заметной разницы. (фред иногда побеждает, иногда читается)
Примечание : медленный mmap
удивителен. Это может быть связано с тем, что я попросил выделить для меня буфер. (Я не был уверен в требованиях к указателю ...)
Короче говоря: не оптимизируйте преждевременно. Заставь его работать, сделай это правильно, сделай это быстро, этот порядок.
Вернувшись по многочисленным просьбам, я запустил тест на реальном файле. (Первые 675 МБ установочного компакт-диска Ubuntu 10.04 с 32-разрядным рабочим столом для ISO) Это были результаты:
# Using fread()
It took 31.363983 seconds to read 675 MiB. That's 21.521501 MiB/s.
It took 31.486195 seconds to read 675 MiB. That's 21.437967 MiB/s.
It took 31.509051 seconds to read 675 MiB. That's 21.422416 MiB/s.
It took 31.853389 seconds to read 675 MiB. That's 21.190838 MiB/s.
# Using read()
It took 33.052984 seconds to read 675 MiB. That's 20.421757 MiB/s.
It took 31.319416 seconds to read 675 MiB. That's 21.552126 MiB/s.
It took 39.453453 seconds to read 675 MiB. That's 17.108769 MiB/s.
It took 32.619912 seconds to read 675 MiB. That's 20.692882 MiB/s.
# Using mmap()
It took 31.897643 seconds to read 675 MiB. That's 21.161438 MiB/s.
It took 36.753138 seconds to read 675 MiB. That's 18.365779 MiB/s.
It took 36.175385 seconds to read 675 MiB. That's 18.659097 MiB/s.
It took 31.841998 seconds to read 675 MiB. That's 21.198419 MiB/s.
... и одному очень программисту позже, мы прочли CD ISO с диска. 12 раз Перед каждым тестом дисковый кэш очищался, и во время каждого теста было достаточно и примерно одинакового объема свободной памяти, чтобы дважды держать CD ISO в оперативной памяти.
Одно интересное замечание: я изначально использовал большой malloc () для заполнения памяти и, таким образом, минимизировал эффекты кеширования диска. Возможно, стоит отметить, что mmap
здесь ужасно выступил. Два других решения просто работали, mmap
запускались и, по причинам, которые я не могу объяснить, начали подталкивать память к обмену, что снижало ее производительность. (Насколько я знаю, программа не протекала (исходный код приведен выше) - фактическая «использованная память» оставалась неизменной на протяжении всех испытаний.)
read () опубликовал самое быстрое время в целом, fread () опубликовал действительно согласованное время. Однако во время тестирования это могло произойти из-за небольшого сбоя. В целом три метода были примерно одинаковыми. (Особенно fread
и read
...)