Многопоточное чтение / работа с символами из массива символов в C - PullRequest
2 голосов
/ 01 мая 2019

Я пытаюсь прочитать массив символов, который содержит содержимое многих больших файлов.Массив символов будет довольно большим, потому что файлы большие, поэтому я хочу сделать это с помощью многопоточности (pthread).Я хочу, чтобы пользователь мог указать, сколько потоков он хочет запустить.У меня что-то работает, но увеличение количества потоков никак не влияет на производительность (то есть 1 поток заканчивается так же быстро, как 10).На самом деле, кажется, что все наоборот: указание программе использовать 10 потоков выполняется намного медленнее, чем указание на использование 1.

Вот метод нарезки массива символов в соответствии с количеством потоковпользователь переходит на программу.Я знаю, что это неправильно, я мог бы использовать некоторые советы здесь.

//Universal variables
int numThreads;
size_t sizeOfAllFiles; // Size, in bytes, of allFiles
char* allFiles; // Where all of the files are stored, together
void *zip(void *nthread);
void *zip(void *nThread) {
     int currentThread = *(int*)nThread;
     int remainder = sizeOfAllFiles % currentThread;
     int slice = (sizeOfAllFiles-remainder) / currentThread;

     // I subtracted the remainder for my testing
     // because I didn't want to worry about whether
     // the char array's size is evenly divisible by numThreads

     int i = (slice * (currentThread-1));
     char currentChar = allFiles[i]; //Used for iterating

     while(i<(slice * currentThread) && i>=(slice * (currentThread-1))) {
        i++;
        // Do things with the respective thread's
        // 'slice' of the array.
        .....
    }
return 0;
}

И вот как я создаю темы, что я почти уверен, что я делаю правильно:

for (int j = 1; j <= threadNum; j++) {
    k = malloc(sizeof(int));
    *k = j;
    if (pthread_create (&thread[j], NULL, zip, k) != 0) {
        printf("Error\n");
        free(thread);
        exit(EXIT_FAILURE);
    }
  }
for (int i = 1; i <= threadNum; i++)
     pthread_join (thread[i], NULL);

Это все действительно сбивает меня с толку, поэтому, если бы я мог получить некоторую помощь по этому вопросу, я был бы очень признателен.Я специально борюсь с нарезкой (правильно ее нарезаю) и не вижу увеличения производительности при использовании более одного потока.Заранее спасибо.

1 Ответ

2 голосов
/ 01 мая 2019

Я начинаю с того, что бросаю в вас тестовую программу:

#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <time.h>


bool
EnlargeBuffer(char ** const buffer_pointer,
              size_t * const buffer_size)
{
  char * larger_buffer = realloc(*buffer_pointer,
                                 2 * *buffer_size);
  if (! larger_buffer) {
    larger_buffer = realloc(*buffer_pointer,
                            *buffer_size + 100);
    if (! larger_buffer) {
      return false;
    }
    *buffer_size += 100;
  } else {
    *buffer_size *= 2;
  }
  *buffer_pointer = larger_buffer;
  printf("(Buffer size now at %zu)\n", *buffer_size);
  return true;
}



bool
ReadAll(FILE * const source,
        char ** pbuffer,
        size_t * pbuffer_size,
        size_t * pwrite_index)
{
  int c;
  while ((c = fgetc(source)) != EOF) {
    assert(*pwrite_index < *pbuffer_size);
    (*pbuffer)[(*pwrite_index)++] = c;
    if (*pwrite_index == *pbuffer_size) {
      if (! EnlargeBuffer(pbuffer, pbuffer_size)) {
        free(*pbuffer);
        return false;
      }
    }
  }
  if (ferror(source)) {
    free(*pbuffer);
    return false;
  }
  return true;
}


unsigned
CountAs(char const * const buffer,
        size_t size)
{
  unsigned count = 0;
  while (size--)
    {
      if (buffer[size] == 'A') ++count;
    }
  return count;
}


int
main(int argc, char ** argv)
{
  char * buffer = malloc(100);
  if (! buffer) return 1;
  size_t buffer_size = 100;
  size_t write_index = 0;
  clock_t begin = clock();
  for (int i = 1; i < argc; ++i)
    {
      printf("Reading %s now ... \n", argv[i]);
      FILE * const file = fopen(argv[i], "r");
      if (! file) return 1;
      if (! ReadAll(file, &buffer, &buffer_size, &write_index))
        {
          return 1;
        }
      fclose(file);
    }
  clock_t end = clock();
  printf("Reading done, took %f seconds\n",
         (double)(end - begin) / CLOCKS_PER_SEC);
  begin = clock();
  unsigned const as = CountAs(buffer, write_index);
  end = clock();
  printf("All files have %u 'A's, counting took %f seconds\n",
         as,
         (double)(end - begin) / CLOCKS_PER_SEC);
}

Эта программа считывает все файлы (переданные в качестве аргументов командной строки) в один большой большой char * buffer,а затем подсчитывает все байты, которые == 'A'.Это также раз оба эти шага.

Пример выполнения с (сокращенным) выводом в моей системе:

# gcc -Wall -Wextra -std=c11 -pedantic allthefiles.c
# dd if=/dev/zero of=large_file bs=1M count=1000
# ./a.out allthefiles.c large_file
Reading allthefiles.c now ... 
(Buffer size now at 200)
...
(Buffer size now at 3200)
Reading large_file now ... 
(Buffer size now at 6400)
(Buffer size now at 12800)
...
(Buffer size now at 1677721600)
Reading done, took 4.828559 seconds
All files have 7 'A's, counting took 0.764503 seconds

Чтение заняло почти 5 секунд , но при подсчете (= итерации один раз в одном потоке свыше всех байт) бит меньше 1 секунды .

Вы оптимизируете не в том месте!

Использование 1 потока для чтения всех файлов, а затем использование N потоков для работы с этим один буфер не принесет вам места. Самый быстрый способ прочитать 1 файл - использовать 1 поток. Для нескольких файлов использовать 1 поток на файл !

Итак, чтобы добиться ускорения,Вы должны показать для своего назначения:

  • Создать пул потоков с переменным размером.

  • Иметь пул задач, где каждая задачасостоит из

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

Что следует учитывать: Как вы объединяете результаты каждогозадача?Без необходимости (дорогостоящей) синхронизации.

...