Fwrite() - эффект размера и рассчитывается на производительность

Кажется, что существует много путаницы в отношении целей двух аргументов "размер" и "счет" в файле fwrite(). Я пытаюсь выяснить, что будет быстрее -

fwrite(source, 1, 50000, destination);

или

fwrite(source, 50000, 1, destination);

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

Теперь я могу просто перейти к тестированию и использовать тот, который дает лучшие результаты, но проблема в том, что код предназначен для МНОГИХ платформ.

Итак,

  • Как я могу получить окончательный ответ, который лучше всего подходит для платформ?

  • Будет ли логика реализации fwrite() изменяться от платформы к платформе?

Я понимаю, что есть похожие вопросы (В чем обоснование для fread/fwrite, принимающего размер и количество аргументов?, Производительность fwrite и размер записи), но поймите, что это другой вопрос по той же проблеме. Ответы по подобным вопросам в этом случае недостаточны.

Ответ 1

Производительность не должна зависеть в любом случае, поскольку любой, кто реализует fwrite, будет умножать размер и подсчет, чтобы определить, сколько операций ввода/вывода делать.

Это проиллюстрировано реализацией libc libc fwrite.c, которая в целом считывает (включая директивы):

/*
 * Write `count' objects (each size `size') from memory to the given file.
 * Return the number of whole objects written.
 */
size_t
fwrite(buf, size, count, fp)
    const void * __restrict buf;
    size_t size, count;
    FILE * __restrict fp;
{
    size_t n;
    struct __suio uio;
    struct __siov iov;

    /*
     * ANSI and SUSv2 require a return value of 0 if size or count are 0.
     */
    if ((count == 0) || (size == 0))
        return (0);

    /*
     * Check for integer overflow.  As an optimization, first check that
     * at least one of {count, size} is at least 2^16, since if both
     * values are less than that, their product can't possible overflow
     * (size_t is always at least 32 bits on FreeBSD).
     */
    if (((count | size) > 0xFFFF) &&
        (count > SIZE_MAX / size)) {
        errno = EINVAL;
        fp->_flags |= __SERR;
        return (0);
    }

    n = count * size;

    iov.iov_base = (void *)buf;
    uio.uio_resid = iov.iov_len = n;
    uio.uio_iov = &iov;
    uio.uio_iovcnt = 1;

    FLOCKFILE(fp);
    ORIENT(fp, -1);
    /*
     * The usual case is success (__sfvwrite returns 0);
     * skip the divide if this happens, since divides are
     * generally slow and since this occurs whenever size==0.
     */
    if (__sfvwrite(fp, &uio) != 0)
        count = (n - uio.uio_resid) / size;
    FUNLOCKFILE(fp);
    return (count);
}

Ответ 2

Назначение двух аргументов становится более понятным, если вы рассматриваете возвращаемое значение, которое представляет собой количество объектов, успешно записанных/прочитанных в/из потока:

fwrite(src, 1, 50000, dst); // will return 50000
fwrite(src, 50000, 1, dst); // will return 1

Скорость может быть зависимой от реализации, хотя я не ожидаю значительных различий.

Ответ 3

Я хотел бы указать вам на мой вопрос, который в итоге показал интересную разницу в производительности между вызовом fwrite и вызовом fwrite несколько раз. напишите файл "в кусках".

Моя проблема заключалась в том, что ошибка в реализации Fwrite в Microsoft, поэтому файлы размером более 4 ГБ не могут быть записаны за один вызов (он зависает при fwrite). Поэтому мне пришлось обойти это, написав файл в кусках, вызвав fwrite в цикле, пока данные не будут полностью записаны. Я обнаружил, что этот последний метод всегда возвращается быстрее, чем единственный вызов fwrite.

Я в Windows 7 x64 с 32 ГБ ОЗУ, что делает кэширование записи довольно агрессивным.