Лучший способ рассчитать результат формулы? - PullRequest
0 голосов
/ 11 февраля 2009

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

Расчеты выполняются на массивах чисел, так что, например, простой A + B может фактически означать сотни добавлений. В настоящее время я использую Delphi, но это не обязательное требование. Я буду использовать инструмент, наиболее подходящий для работы. Формулы также могут зависеть друг от друга. Таким образом, у нас может быть одна формула C = A + B и вторая, например, D = C + A.

Ответы [ 2 ]

1 голос
/ 13 февраля 2009

Давайте предположим, что ваши формулы (уравнения) не являются циклическими, так как в противном случае вы не можете «просто» оценить их. Если у вас есть векторизованные уравнения, такие как A = B + C, где A, B и C являются массивами, давайте концептуально разделим их на уравнения для компонентов, так что если размер массива равен 5, это уравнение будет разбито на

a1 = b1 + c1
a2 = b2 + c2
...
a5 = b5 + c5

Теперь, предполагая это, у вас есть большой набор уравнений для простых величин (целых, рациональных или что-то еще).

Если у вас есть два уравнения E и F, скажем, что F зависит от E, если правая часть F упоминает левую часть E, например

E: a = b + c
F: q = 2*a + y

Теперь, чтобы перейти к тому, как рассчитать это, вы всегда можете использовать рандомизированную итерацию, чтобы решить это (это всего лишь промежуточный шаг в объяснении), следуя этому алгоритму:

1 while (there is at least one equation which has not been computed yet)
2   select one such pending equation E so that:
3     for every equation D such that E depends_on D:
4       D has been already computed
5   calculate the left-hand side of E

Этот процесс завершается с правильным ответом, независимо от того, как вы делаете выбор в строке // 2. Теперь круто то, что он также легко распараллеливается. Вы можете запустить его в произвольном количестве потоков! То, что вам нужно, это безопасная для параллелизма очередь, которая содержит те уравнения, чьи предпосылки (от которых зависят эти уравнения) были вычислены, но которые еще не были вычислены сами. Каждый поток выдает (потокобезопасно) одно уравнение из этой очереди за раз, вычисляет ответ, а затем проверяет, существуют ли теперь новые уравнения, чтобы были вычислены все их предпосылки, а затем добавляет эти уравнения (потокобезопасно) в очередь на работу. Готово.

1 голос
/ 11 февраля 2009

Не зная больше, я бы посоветовал использовать подход в стиле SIMD, если это возможно. То есть создайте потоки для вычисления всех формул для одного набора данных. Попытка разделить вычисления формул для их распараллеливания не приведет к значительному повышению скорости, так как логика, необходимая для разделения вычислений на отдельные единицы, пригодные для многопоточности, будет трудной для написания и труднее для правильной, накладные расходы будут отменены любой прирост скорости. Он также быстро пострадал бы от уменьшения отдачи.

Теперь, если у вас есть набор формул, которые применяются ко многим наборам данных, распараллеливание становится проще и масштабируется лучше. Каждый поток выполняет все вычисления для одного набора данных. Создайте один поток на ядро ​​ЦП и установите его привязку к каждому ядру. Каждый поток создает один экземпляр кода оценки формулы. Создайте супервизор, который загружает один набор данных и передает ему свободный поток. Если ни один из потоков не занят, подождите, пока первый поток завершит обработку своих данных. Когда все наборы данных обработаны и все потоки завершены, завершите работу. Используя этот метод, нет никакого преимущества в том, чтобы иметь больше потоков, чем количество ядер в ЦП, поскольку переключение потоков происходит медленно и отрицательно влияет на общую скорость.

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

...