2010-06-05 2 views
14

Я пишу книгу по многоядерному программированию с использованием .NET 4, и мне любопытно узнать, какие части многоядерных программистов люди трудно найти или предвидеть, что их трудно перехватить?Многоядерное программирование: жесткие части

+0

флажок «community wiki» в правом нижнем углу, когда вы редактируете сообщение. – kennytm

+3

У вас нет прав на wiki ваш пост, если вы этого не хотите. Wiki означает «редактируемый кем-либо» и что вы хотите, чтобы сообщество взяло на себя ответственность за ваше сообщение, оно не используется для классификации «субъективных» или «дискуссионных» вопросов, поскольку у нас уже есть теги по этой причине. – Juliet

+2

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

ответ

3

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

Большинство остальных концепций и идей (что-либо может чередовать, условия гонки, ...) не так сложно с небольшим использованием.

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

2

Его не столько теоретические детали, сколько больше деталей практической реализации, которые вызывают людей.

В чем заключаются сделки с неизменяемыми структурами данных?

Все время, люди пытаются обновить структуру данных из нескольких потоков, найти это слишком трудно, и кто-то вмешивается, и поэтому наш постоянный Кодер пишет об этом «использовать неизменные структуры данных!»:

ImmutableSet set; 

ThreadLoop1() 
    foreach(Customer c in dataStore1) 
     set = set.Add(ProcessCustomer(c)); 

ThreadLoop2() 
    foreach(Customer c in dataStore2) 
     set = set.Add(ProcessCustomer(c)); 

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

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

Как распределить примерно равное количество работ между потоками?

Правильный шаг: hard. Иногда вы разбиваете один процесс на 10 000 шагов, которые могут выполняться параллельно, но не все шаги занимают одинаковое количество времени. Если вы разделите работу на 4 потока, а первые 3 потока заканчиваются через 1 секунду, а последний поток занимает 60 секунд, ваша многопоточная программа не намного лучше, чем однопоточная версия, верно?

Итак, как вы разделяете проблемы с примерно равным объемом работы между всеми потоками? Здесь должно быть уместно много хороших эвристик при решении проблем с упаковкой бункеров.

Сколько потоков?

Если ваша проблема хорошо распараллеливается, добавление большего количества потоков должно ускориться, не так ли? Ну, на самом деле не так много вещей, чтобы рассмотреть здесь:

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

Итак, как вы можете сократить количество потоков, чтобы минимизировать время выполнения?

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

+0

Джон - большой сторонник функционального программирования, который действительно меняет, какие задачи сложны. Наверное, вы пропустили тег «f #» на вопросе, он должен был указать на его функциональный подход. Упаковка бина может быть одним из подходов к разделению, но работа-кража и рабочие очереди, где разбиение не определяется априорно, кажутся намного более популярными в реальном мире. –

+0

@Ben: Обратите внимание, что я защищаю нечистые функциональные языки, такие как F #, и вообще не избегаю мутации и изменяемых структур данных. Действительно, я считаю, что мутация часто необходима в контексте параллелизма. –

5

Поскольку вы пишете целую книгу для многоядерного программирования в .Net.

Я думаю, вы также можете выходить за рамки многоядерных немного.

Например, вы можете использовать главу, посвященную параллельным вычислениям в распределенной системе в .Net. Маловероятно, что в .Net еще нет зрелых фреймворков. DryadLinq является самым близким. (С другой стороны, Hadoop и его друзья на платформе Java действительно хороши.)

Вы также можете использовать главу, демонстрирующую некоторые вычислительные средства графического процессора.

6

Я думаю, что некоторые из них зависят от того, насколько основной или продвинутой книга/аудитория. Когда вы переходите от однопоточного к многопоточному программированию в первый раз, вы обычно отваливаетесь от огромного утеса (и многие из них никогда не восстанавливаются, см., Например, все запутанные вопросы о Control.Invoke).

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

  • Измерение: решить, что метрический вы стремитесь улучшить, правильно измерить его (так легко случайно измерить неправильную вещь), используя правильные инструменты, дифференцируя сигнал против шума, интерпретируя результаты и понимая, почему они такие, каковы они есть.

  • Тестирование: как написать тесты, которые допускают неважные детерминизм/перемежения, но все же вызывают правильное поведение программы.

  • Debugging: инструменты, стратегия, когда «трудно отлаживать» подразумевает обратную связь, чтобы улучшить свой код/​​дизайн и более разделы изменяемого состояние и т.д.

  • Физических против логического сродства нити: понимание Пользовательский интерфейс, понимающий, как, например, F # MailboxProcessor/agent может инкапсулировать изменяемое состояние и работать на нескольких потоках, но всегда с одним логическим потоком (один счетчик программ).

  • Шаблоны (и когда они применяются): вилочные присоединиться, карта-свертка, производитель-потребитель, ...

Я ожидаю, что будет большая аудитория, например, «help, у меня однопоточное приложение с 12% -ным использованием процессора, и я хочу узнать достаточно, чтобы сделать его быстрее на 4 раза без большой работы» и меньшую аудиторию, например. «мое приложение масштабируется сублинейно, так как мы добавляем ядра, потому что здесь, кажется, существует спор, есть ли более эффективный подход к использованию?», и поэтому проблема может быть в обслуживании каждой из этих аудиторий.

+0

Что касается тестирования, моя компания работала в инструменте Microsoft CHESS (http://research.microsoft.com/en-us/projects/chess/), чтобы исчерпывающе протестировать все перемежения нашего многопоточного кода, и это было чисто потрясающе из начните заканчивать. Вероятно, это может быть полезно здесь. – Juliet

7

Что такое полезная единица работы для распараллеливания и как ее найти/организовать?

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

Таким образом, одна из больших проблем - найти единицы работы, которые, очевидно, дороже, чем примитивы параллелизма. Ключевой проблемой здесь является то, что никто не знает, что нужно затратить на выполнение, включая сами примитивы параллелизма. Четкая калибровка этих затрат будет очень полезной. (В стороне мы разработали, внедрили и ежедневно использовали параллельное программирование langauge, PARLANSE, целью которого было минимизировать затраты на примитивы параллелизма, позволяя компилятору генерировать и оптимизировать их с целью создания меньших бит работы " более параллелизуемым ").

Можно также рассмотреть возможность обсуждения большого числа обозначений и приложений. Мы все надеемся, что примитивы параллелизма стоят O (1). Если это так, то если вы найдете работу со стоимостью O (x)> O (1), то эта работа является хорошим кандидатом для распараллеливания. Если ваша предлагаемая работа также является O (1), то насколько она эффективна или не зависит от постоянных факторов, и мы вернемся к калибровке, как указано выше.

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

Наконец, проблема синхронности: когда мои параллельные юниты должны взаимодействовать, какие примитивы я должен использовать, и сколько стоят этих примитивов? (Больше, чем вы ожидаете!).

4

Одна вещь, которая меня опрокинула, - это какой подход использовать для решения определенного типа проблем. Есть агенты, есть задачи, асинхронные вычисления, MPI для распространения - для многих проблем вы можете использовать несколько методов, но мне трудно понять, почему я должен использовать один над другим.

1

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

Обычно я считаю, что отладка тоже будет медведем.

Смежные вопросы