Загадочная комбинация - PullRequest
1 голос
/ 10 апреля 2010

Я решил изучить параллелизм и хотел выяснить, как много способов могут перекрываться инструкциями из двух разных процессов. Код для обоих процессов представляет собой всего лишь 10-итерационный цикл с 3 инструкциями, выполняемыми в каждой итерации. Я выяснил, что проблема состоит в том, чтобы оставить X-инструкции фиксированными в некоторой точке, а затем поместить другие X-инструкции из другого процесса между пробелами, учитывая, что они должны быть упорядочены (инструкция 4 процесса B всегда должна предшествовать инструкции 20).

Я написал программу для подсчета этого числа, глядя на результаты, которые я обнаружил, что решением является n Комбинация k, где k - это количество инструкций, выполненных на протяжении всего цикла одного процесса, поэтому для 10 итераций это будет 30, а n равно k * 2 (2 процесса). Другими словами, n объектов с фиксированным n / 2 и необходимостью размещения n / 2 среди пробелов, при этом последние n / 2 не теряют своего порядка.

Хорошо, проблема решена. Нет, не совсем. Я понятия не имею, почему это так, я понимаю, что определение комбинации состоит в том, во сколько раз вы можете взять k элементов из группы n, чтобы все группы были разными, но порядок, в котором вы берете элементы, не ' не имеет значения. В этом случае у нас есть n элементов, и мы фактически берем их все, потому что все инструкции выполнены (n C n).

Если кто-то объясняет это тем, что в сумке есть 2k синих (A) и красных (B) объектов, и вы берете k предметов из сумки, вы все равно берете только k инструкций, когда фактически выполняется 2k инструкций. Не могли бы вы пролить свет на это?

Заранее спасибо.

Ответы [ 3 ]

6 голосов
/ 10 апреля 2010

FWIW это можно посмотреть так: у вас есть сумка с k синим и k красным шариками. Шарики одного цвета неразличимы (по аналогии с ограничением, что порядок инструкций в одном и том же процессе / потоке фиксирован - что не так в современных процессорах, между прочим, но давайте пока оставим это простым). Сколько разных способов вы можете вытащить все шарики из сумки?

Мои комбинаторные навыки довольно ржавые, но мое первое предположение -

(2k!)
-----
2*k!

, который, согласно Википедии , действительно равен

(2k)
(k )

(извините, я понятия не имею, как это показать).

Для процессов n его можно обобщить, имея в мешках шарики n другого цвета.

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

2 голосов
/ 10 апреля 2010

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

У вас есть 2 набора по 30 (k) инструкций, которые вы собираете, в общей сложности 60 (n) инструкций. Так как каждый набор из 30 должен храниться в порядке, нам не нужно отслеживать, какая инструкция в каждом наборе, а только от того, из какого набора была получена инструкция. Итак, у нас есть 60 «слотов» для размещения 30 инструкций из одного набора (скажем, красного цвета) и 30 инструкций из другого набора (скажем, синего цвета).

Давайте начнем с размещения 30 красных инструкций в 60 слотов. Есть (60 выберите 30) = 60! / (30! 30!) Способов сделать это (мы выбираем, какие 30 слотов из 60 заполнены красными инструкциями). Теперь у нас еще есть 30 синих инструкций, но у нас осталось только 30 открытых слотов. Существует (30 выберите 30) = 30! / (30! 0!) = 1 способ поместить синие инструкции в оставшиеся слоты. Таким образом, всего есть (60 выбрать 30) * (30 выбрать 30) = (60 выбрать 30) * 1 = (60 выбрать 30) способов сделать это.

Теперь давайте предположим, что вместо 2 наборов по 30 у вас есть 3 набора (красный, зеленый, синий) из k инструкций. У вас есть 3k слотов для заполнения. Сначала поместите красные: (3k выберите k) = (3k)! / (K! (3k-k)!) = (3k)! / (K! (2k)!). Теперь поместите зеленые в оставшиеся 2k слотов: (2k выберите k) = (2k)! / (K! K!). Наконец, поместите синие в последние k слотов: (k выберите k) = k! / (K! 0!) = 1. Всего: (3k выберите k) * (2k выберите k) * (k выберите k) = ((3k)! * (2k)! * K!) / (K! (2k)! * K! K! * K! 0!) = (3k)! / (K! K! K!).

В качестве дополнительных расширений (хотя я не буду приводить полное объяснение):

  • если у вас есть 3 набора инструкций с длиной a, b и c, количество возможностей составляет (a + b + c)! / (A! B! C!).
  • если у вас есть n наборов инструкций, в которых i-й набор содержит ki-инструкции, количество возможностей будет (k1 + k2 + ... + kn)! / (K1! K2! ... kn!).
1 голос
/ 10 апреля 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...