Как я могу эффективно проиндексировать неквадратную матрицу продукта среди n потоков?

Предположим, я хочу использовать многопоточность для умножения матрицы i × j на матрицу j × k, чтобы получить матрицу i × k, где i, j и k неизвестны. Число потоков n, которым поручено выполнение умножения матриц, также неизвестно. Как я могу эффективно определить индексы матрицы продуктов, за вычисление которых отвечает каждый поток?

Для справки, мой первоначальный подход заключался в том, чтобы разделить общее количество элементов (произведение i и k) на количество потоков (n), чтобы получить количество индексов, за которые отвечает каждый поток. При создании каждого потока он передавал свой номер (т. Е. Поток 0, 1, 2 ...) методу умножения, чтобы определить начальный и конечный индексы, как если бы матрица была одномерной (то есть [0] [0] = 0, [0] [1] = 1, [0] [2] = 2 ...). Наконец, метод будет перебирать каждый одномерный индекс, преобразовывать его в его двумерный аналог и определять значение для каждого индекса.

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

Вот моя реализация на случай, если приведенное выше описание не было ясным:

public synchronized void perform(int id) {
    int first = id * NUM_OPS;
    int last = first + NUM_OPS - 1;

    if (id == NUM_THREADS - 1)
        last += (i * k) % NUM_THREADS;

    if (last >= i * k)
        return;

    for(int curr = first; curr <= last; curr++) {
        int p = curr / k;
        int r = curr % k;
        for(int q = 0; q < j; q++)
            C[p][r] += A[p][q] * B[q][r];
    }
}

Вы сказали «эффективно», верно? Тогда «Как создавалась каждая ветка» противоречит вашим целям, потому что запуск потоков выполняется медленно. Вы должны использовать пул потоков.

Andreas 04.10.2018 23:44

@Andreas В итоге все получилось очень хорошо, спасибо! Однако я все еще не уверен, почему мой первоначальный подход был медленным. Возможно, моя реализация на самом деле не была параллельной.

Jordan 05.10.2018 08:47
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3
2
51
0

Другие вопросы по теме