Обработка многопоточного массива и запись в результирующий массив для расширения C-Python - PullRequest
0 голосов
/ 19 февраля 2019

Код ниже является расширением C-Python.Этот код берет входной буфер непрерывных необработанных байтов (для моего приложения - "блоки" необработанных байтов, где 1 блок = 128 байтов), а затем обрабатывает эти байты в 2-байтовые "выборки", помещая результат в товар .Возвращенная структура - это просто буфер, обработанный в целые числа Python.

Вот 2 основные функции:

unpack_block (items, items_offset, buffer, buffer_offset, samples_per_block, sample_bits);

Затем цикл проходит через каждый образец в элементах и затем преобразует каждый образец в Python Int.

PyList_SET_ITEM (result, index, PyInt_FromLong (items [index]));

    unsigned int num_blocks_per_thread, num_samples_per_thread, num_bytes_per_thread;
    unsigned int thread_id, p;
    unsigned int n_threads, start_index_bytes, start_index_blocks, start_index_samples;

    items = malloc(num_samples*sizeof(unsigned long));
    assert(items);

    #pragma omp parallel\
    default(none)\
    private(num_blocks_per_thread, num_samples_per_thread, num_bytes_per_thread, d, j, thread_id, n_threads, start_index_bytes, start_index_blocks, start_index_samples)\
    shared(samples_per_block, num_blocks, buffer, bytes_per_block, sample_bits, result, num_samples, items)
      {

        n_threads = omp_get_num_threads();
        num_blocks_per_thread = num_blocks/n_threads;
        num_samples_per_thread = num_samples/n_threads; 
        num_bytes_per_thread = num_blocks_per_thread*samples_per_block*2/n_threads;

        thread_id = omp_get_thread_num();
        start_index_bytes = num_bytes_per_thread*thread_id;
        start_index_blocks = num_blocks_per_thread*thread_id;  
        start_index_samples = num_samples_per_thread*thread_id;

        for (d=0; d<num_blocks_per_thread; d++) {
          unpack_block(items, start_index_samples+d*samples_per_block, buffer, start_index_blocks + d*bytes_per_block, samples_per_block, sample_bits);
        }

      }

     result = PyList_New(num_samples);
     assert(result);

     //*THIS WOULD ALSO SEEM RIPE FOR MULTITHREADING*
     for (p=0; p<num_samples; p++) {
        PyList_SET_ITEM(result, p, PyInt_FromLong( items[p] ));
      }

    free(items);
    free(buffer);

  return result;
}

Скорость просто ужасна и намного меньше, чем я ожидаю от многопоточности.У меня может возникнуть проблема с ложным разделением, когда потоки записывают данные в разные блоки массива items , хотя каждый поток обрабатывает только взаимоисключающие блоки одного и того же массива.

Фундаментальный вопрос для меня: как правильно многопоточно обрабатывать отдельный элемент массива, а затем выводить результат для каждого элемента во второй массив «result».Я выполняю это дважды с помощью двух своих функций.

Любые идеи, решения или способы оптимизации будут великолепны.Спасибо!

1 Ответ

0 голосов
/ 19 февраля 2019

Вы уже упомянули ложный обмен.Чтобы избежать этого, вы должны соответствующим образом распределить память (используя posix_memalign или другую выровненную функцию выделения), а также выбрать размер фрагмента так, чтобы размер данных одного фрагмента был точно кратным размеру строки кэша.

Как правило, измерьте время выполнения, используя потоки $ N $, и рассчитайте ускорение.Можете ли вы поделиться с нами кривой ускорения?

Что касается комментария "Это может показаться созревшим для многопоточности": часто ожидания слишком высоки (просто как предупреждение, чтобы избежать разочарования).Подумайте, сколько потоков / элементов на поток вы используете и какова нагрузка на поток (т. Е. Сколько вычислений требуется для каждого элемента).Возможно, рабочая нагрузка настолько мала, что накладные расходы OpenMP доминируют.Кроме того, сколько инструкций требуется для каждой операции загрузки памяти?Как правило, многие инструкции на загрузку памяти являются разумными кандидатами для распараллеливания.Низкий коэффициент указывает на то, что программа связана с памятью.

Говоря о доступе к памяти, вы работаете в системе с несколькими сокетами и разными доменами NUMA?Если да, вы должны позаботиться о проблемах сродства.

...