C: Как прочитать часть файла кусками - PullRequest
0 голосов
/ 22 ноября 2018

Я должен реализовать для назначения курса алгоритм шифрования и дешифрования Хаффмана сначала классическим способом, затем я должен попытаться сделать его параллельным, используя различные методы (openMP, MPI, phtreads).Цель проекта не в том, чтобы сделать его обязательно быстрее, а в том, чтобы проанализировать результаты и поговорить о них и почему они такие.

Серийная версия работает отлично.Однако для параллельной версии я наткнулся на проблему чтения из файла.В серийной версии у меня есть кусок кода, который выглядит следующим образом:

char *buffer = calloc(1, MAX_BUFF_SZ);

while (bytes_read = fread(buffer, 1, MAX_BUFF_SZ, input) > 0) {
    compress_chunk(buffer, t, output);
    memset(buffer, 0, MAX_BUFF_SZ);
}

Это читает не более MAX_BUFF_SZ байтов из входного файла, а затем шифрует их.Я использовал вызов memset для случая, когда bytes_read < MAX_BUFF_SZ (возможно, существует более чистое решение).

Тем не менее, для параллельной версии (например, с использованием openMP) я хочу, чтобы каждый поток анализировал только часть файла, но чтение по-прежнему выполняется фрагментами.Зная, что у каждого потока есть и id thread_id, а их максимум total_threads, я рассчитываю начальную и конечную позиции следующим образом:

int slice_size = (file_size + total_threads - 1) / total_threads;
int start = slice_size * thread_id;
int end = min((thread_id + 1) * slice_size, file_size);

Я могу перейти в начальную позицию простым fseek(input, start, SEEK_SET) операция.Тем не менее, я не могу читать содержимое по частям.Я попытался с помощью следующего кода (просто чтобы убедиться, что операция в порядке):

int total_bytes = 0;
while ((bytes_read = fread(buffer, 1, MAX_BUFF_SZ, input)) > 0) {
    total_bytes += bytes_read;

    if (total_bytes >= end) {
        int diff = total_bytes - end;
        buffer[diff] = '\0';
        break;
    }

    fwrite(buffer, 1, bytes_read, output);
    memset(buffer, 0, MAX_BUFF_SZ);
}

output - это отдельный файл для каждого потока.Даже когда я пробую только 2 темы, в них есть некоторые недостающие символы.Я думаю, что я близок к правильному решению, и у меня есть что-то вроде ошибки по одному.

Итак, вопрос: как я могу прочитать фрагмент файла, но кусками? Не могли бы вы помочь мне выявить ошибку в приведенном выше коде и заставить ее работать?

Редактировать : Если MAX_BUFF_SZ будет больше, чем размер ввода, и янапример, 4 потока, как должен выглядеть чистый код, чтобы гарантировать, что T0 выполнит всю работу, а T1, T2 и T3 ничего не сделают?

Какой-то простой код, который можетДля проверки поведения используется следующее (обратите внимание, что это не из кода Хаффмана, это некоторый вспомогательный код для проверки вещей):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <omp.h>

#define MAX_BUFF_SZ 32

#define min(a, b) \
   ({ __typeof__ (a) _a = (a); \
       __typeof__ (b) _b = (b); \
     _a < _b ? _a : _b; })

int get_filesize(char *filename) {
    FILE *f = fopen(filename, "r");
    fseek(f, 0L, SEEK_END);
    int size = ftell(f);
    fclose(f);

    return size;
}

static void compress(char *filename, int id, int tt) {
    int total_bytes = 0;
    int bytes_read;
    char *newname;
    char *buffer;
    FILE *output;
    FILE *input;
    int fsize;
    int slice;
    int start;
    int end;

    newname = (char *) malloc(strlen(filename) + 2);
    sprintf(newname, "%s-%d", filename, id);

    fsize = get_filesize(filename);
    buffer = calloc(1, MAX_BUFF_SZ);

    input = fopen(filename, "r");
    output = fopen(newname, "w");

    slice = (fsize + tt - 1) / tt;
    end = min((id + 1) * slice, fsize);
    start = slice * id;

    fseek(input, start, SEEK_SET);

    while ((bytes_read = fread(buffer, 1, MAX_BUFF_SZ, input)) > 0) {
        total_bytes += bytes_read;
        printf("%s\n", buffer);

        if (total_bytes >= end) {
            int diff = total_bytes - end;
            buffer[diff] = '\0';
            break;
        }

        fwrite(buffer, 1, bytes_read, output);
        memset(buffer, 0, MAX_BUFF_SZ);
    }

    fclose(output);
    fclose(input);
}

int main() {
    omp_set_num_threads(4);
    #pragma omp parallel
    {
        int tt = omp_get_num_threads();;
        int id = omp_get_thread_num();
        compress("test.txt", id, tt);
    }
}

Вы можете скомпилировать его с помощью gcc test.c -o test -fopenmp.Вы можете сгенерировать файл test.txt с некоторыми случайными символами, более 32 (или изменить максимальный размер буфера).

Редактировать 2 : Опять же, моя проблема заключается в чтении фрагментафайл кусками, а не анализ как таковой.Я знаю, как это сделать.Это университетский курс, я не могу просто сказать «IO-связанный, конец истории, анализ завершен».

1 Ответ

0 голосов
/ 23 ноября 2018

Очевидно, мне просто нужно было взять ручку и бумагу и сделать небольшую схему.Поработав с некоторыми индексами, я получил следующий код (encbuff и written_bits - некоторые вспомогательные переменные, которые я использую, поскольку я на самом деле записываю биты в файл и использую промежуточный буфер для ограничения записей):

while ((bytes_read = fread(buffer, 1, MAX_BUFF_SZ, input)) > 0) {
        total_bytes += bytes_read;

        if (start + total_bytes > end) {
            int diff = start + total_bytes - end;
            buffer[bytes_read - diff] = '\0';
            compress_chunk(buffer, t, output, encbuff, &written_bits);
            break;
        }

        compress_chunk(buffer, t, output, encbuff, &written_bits);
        memset(buffer, 0, MAX_BUFF_SZ);
}

Я также завершил реализацию версии openMP.Для небольших файлов последовательный файл быстрее, но начиная с 25 МБ, параллельный начинает бить последовательный с 35-45%.Спасибо всем за совет.

Ура!

...