Что такое общие ловушки параллелизма? [закрытый]

Использование метода getRange. getRangeByName

. Примечание.

31
задан casperOne 6 April 2012 в 17:52
поделиться

21 ответ

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

НЕ ПОЛАГАЮТСЯ НА ТЕСТИРОВАНИЕ ДЛЯ НАХОЖДЕНИЯ УСЛОВИЙ СОСТЯЗАНИЯ И МЕРТВЫХ БЛОКИРОВОК

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

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

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

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

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

Быть параноидальным. очень параноидальный.

17
ответ дан 27 November 2019 в 21:42
поделиться

Проблемы параллелизма невероятно трудно отладить. Как профилактическая мера, можно полностью запретить доступ к общим объектам, не используя взаимные исключения таким способом, которым программисты могут легко следовать правилам. Я видел сделанный путем создания оберток вокруг обеспеченных ОС взаимных исключений, и семафоры, и т.д.

Вот некоторые запутывающие примеры от моего прошлого:

я раньше разрабатывал драйвера принтера для Windows. Чтобы препятствовать тому, чтобы несколько потоков писали в принтер одновременно, наш монитор порта использовал конструкцию как это://псевдо код, потому что я не могу помнить API BOOL OpenPort () {GrabCriticalSection ();} BOOL ClosePort () {ReleaseCriticalSection ();} BOOL WritePort () {writestuff ();}

, К сожалению, каждый вызов к WritePort был от различного потока в пуле потоков спулера. Мы в конечном счете вошли в ситуацию, где OpenPort и ClosePort назвали различные потоки, вызвав мертвую блокировку. Решение для этого оставляют как осуществление, потому что я не могу помнить то, что я сделал.

я также раньше работал над встроенным микропрограммным обеспечением принтера. Принтер в этом случае использовал RTOS, названный uCOS (объявленный 'слизью'), таким образом, каждая функция имела свою собственную задачу (двигатель печатающей головки, последовательный порт, параллельный порт, сетевой стек, и т.д.). Одна версия этого принтера имела внутреннюю опцию, которая включила последовательный порт на материнской плате принтера. В какой-то момент было обнаружено, что принтер считает тот же результат дважды из этого периферийного устройства и каждого значения там после того, как был бы вне последовательности. (например, периферийное устройство считало последовательность 1 7 3 56 9 230, но мы видели бы 1 7 3 3 56 9 230. Это значение становилось сообщаемым компьютеру и помещенным в базу данных также - груда документов с неправильными Идентификационными номерами была Очень Плоха), первопричиной этого был отказ уважать взаимное исключение, которое защищало буфер чтения для устройства. (Следовательно мой совет в начале этого ответа)

0
ответ дан 27 November 2019 в 21:42
поделиться

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

Лично, я - преобразование в модель Actor параллельного вычисления (асинхронное разнообразие).

0
ответ дан 27 November 2019 в 21:42
поделиться

Это не ловушка, но больше подсказки на основе ответов других. readerwriterlockslim платформы.NET существенно улучшит Вашу производительность во многих случаях по оператору "блокировки", будучи повторно используемым.

0
ответ дан 27 November 2019 в 21:42
поделиться

Также Вы могли посмотреть на проблемы параллелизма типа из процесса
, Например:
процесс устройства записи А, делающий файл и потребительский процесс, требуя файла.

0
ответ дан 27 November 2019 в 21:42
поделиться

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

0
ответ дан 27 November 2019 в 21:42
поделиться

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

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

  2. Представление блокирует излишне. , Если нет никакой потребности выставить блокировку, то это, считают хранение скрытым. Иначе клиенты могут использовать его и создать мертвые блокировки, которые Вы, возможно, предотвратили.

Вот простое пример № 1 выше , один это достаточно близко к чему-то, что я видел в производственном коде:

public class CourseService {
    private CourseDao courseDao;
    private List courses;

    public List getCourses() {
        this.courses = courseDao.getCourses();
        return this.courses;
    }
}

В этом примере нет никакой потребности в courses переменная, чтобы иметь объем экземпляра, и теперь параллельные вызовы к getCourses() могут иметь гонки.

1
ответ дан 27 November 2019 в 21:42
поделиться

Некоторые эмпирические правила:

(1) Следят за контекстом, когда Ваш объявляла, что переменная

  • , Запись классифицирует атрибуты ( статичный ) должна синхронизироваться
  • , Запись для инстанцирования атрибутов должна синхронизироваться
  • , Сохраняют все переменные максимально локальными (не помещайте их в членский контекст, если это не имеет смысл)
  • переменные Mark, которые являются только для чтения неизменный

(2) Блокировка доступ к изменяемому классу или атрибутам экземпляра: Переменные, которые являются частью того же инвариант , должны быть защищены той же блокировкой.

(3) Избегают , Проверенная дважды Блокировка

(4) Сохраняет блокировки, когда Вы работаете , распределил операция (назовите подпрограммы).

(5) Избегают , активное ожидание

(6) Поддерживает рабочую нагрузку на низком уровне в синхронизируемых разделах

(7), не позволяют брать на себя клиентское управление, в то время как Вы находитесь в синхронизируемом блоке.

(8) Комментарии! Это действительно помогает понять то, что другой парень имел в виду с объявлением этого синхронизируемого раздела или та неизменная переменная.

1
ответ дан 27 November 2019 в 21:42
поделиться

Вызов общедоступных классов из блокировки, вызывающей DeadLock

public class ThreadedClass
{
    private object syncHandle = new object();

    public event EventHandler Updated = delegate { };
    public int state = 0;

    public void DoSmething()
    {
        lock(syncHandle)
        {
            // some locked code
            state = 1;

            Updated(this, EventArgs.Empty);
        }
    }

    public int State { 
        get
        {
            int returnVal;
            lock(syncHandle)
                returnVal = state;
            return returnVal;            
        }
    }
}

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

public void DoSmething()
{
    lock(syncHandle)
    {
        // some locked code
        state = 1;
    }
    // this should be outside the lock
    Updated(this, EventArgs.Empty);
}
1
ответ дан 27 November 2019 в 21:42
поделиться

Перепроверяемая блокировка повреждена , по крайней мере, в Java. Понимание, почему это верно, и как можно зафиксировать его, приводит Вас глубоко в понимание проблем параллелизма и модели памяти Java.

1
ответ дан 27 November 2019 в 21:42
поделиться

Ловушка № 1, которую я видел, является слишком большим совместным использованием данных.

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

2
ответ дан 27 November 2019 в 21:42
поделиться

По моему опыту, многие (квалифицированные) разработчики испытывают недостаток в основополагающем знании о теории параллелизма. Классические учебники по Операционным системам Tanenbaum или Stallings делают хорошее задание в объяснении теории и последствий параллелизма: Взаимное исключение, синхронизация, мертвые блокировки и исчерпание ресурсов. Хороший теоретический фон обязателен для успешной работы с параллелизмом.

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

2
ответ дан 27 November 2019 в 21:42
поделиться

Все это сводится к совместно используемым данным / общее состояние. Если Вы не совместно используете данных или заявляете затем, что у Вас нет проблем параллелизма.

Большинство людей, когда они думают о параллелизме, думает о многопоточности в единственном процессе.

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

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

(Остальная часть этого не относится к поточной обработке Java, которую я не использую и поэтому знаю мало о).

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

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

Удачи!

3
ответ дан 27 November 2019 в 21:42
поделиться

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

Слишком часто люди идут сумасшедший поток/задача. Все работает над его собственным потоком. Конечный результат состоит в том, что почти каждая часть кода должна глубоко знать о поточной обработке проблем. Это вынуждает в других отношениях простой код быть замусоренным блокировкой и синхронизацией confuscations. Каждый раз I’ve, замеченный, это, система в конечном счете становится неудобной в сопровождении путаницей. Все же, каждый раз I’ve, замеченный это, исходные разработчики все еще настаивают, что это был хороший дизайн: (

Как множественное наследование, если Вы хотите создать новый поток / задача затем, предполагают, что Вы неправильно до доказаны иначе. Я can’t даже считают количество раз, что I’ve, замеченный Поток шаблона B thenThread B Потока вызовов, называет Поток C затем Поток C, называю D всем ожиданием ответа из предыдущего сообщения. Весь код делает, делает многоречивые вызовы функции через различные потоки. Don’t используют потоки, когда вызовы функции работают просто великолепно.

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

я нашел, что создание базовой инфраструктуры, которая обрабатывает почти все работы проблем параллелизма лучше всего. Если существуют какие-либо потоки за пределами базовой инфраструктуры, которая должна говорить с другой частью программного обеспечения затем, они должны пройти базовую инфраструктуру. Тем путем остальная часть системы может остаться не зная параллелизмом, и проблемы параллелизма могут быть обработаны человеком (людьми), кто, надо надеяться, понимает параллелизм.

3
ответ дан 27 November 2019 в 21:42
поделиться

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

Параллелизм, конечно, неизбежен в некоторых доменах, но когда это преодолимо, избегайте его.

10
ответ дан 27 November 2019 в 21:42
поделиться

Как указано в других ответах, две наиболее вероятных проблемы мертвые блокировки и условия состязания . Однако мой основной совет состоял бы в том, что, если бы Вы надеетесь обучать команду на предмет параллелизма, я настоятельно рекомендовал бы получение некоторого обучения сами . Получите хорошую книгу по предмету, не полагайтесь на несколько абзацев с веб-сайта. Хорошая книга зависела бы от языка, который Вы используете: "Параллелизм Java на практике" Brian Goetz хорош для того языка, но существует много других.

3
ответ дан 27 November 2019 в 21:42
поделиться

Я преподаю параллелизм много моим друзьям и коллегам. Вот некоторые большие ловушки:

  • Предположение, что переменная, которая главным образом считана во многих потоках и только записана в одном потоке, не должна быть заблокирована. (В Java эта ситуация может привести к потокам чтения никогда наблюдение нового значения.)
  • Предположение, что потоки будут работать в особом порядке.
  • Предположение, что потоки будут работать одновременно.
  • Предположение, что потоки НЕ будут работать одновременно.
  • Предположение, что все потоки сделают вперед успехи перед любым из концов потоков.

я также вижу:

  • Большие беспорядки между thread_fork() и fork().
  • Беспорядки, когда память выделяется в одном потоке и free() d в другом потоке.
  • Беспорядки, следующие из того, что некоторые библиотеки ориентированы на многопотоковое исполнение и некоторые не.
  • Люди, использующие спин-блокировки, когда они должны использовать сон & не спящий или избранный, или безотносительно блокирующегося механизма Ваши поддержки языка.
12
ответ дан 27 November 2019 в 21:42
поделиться

Параллелизм не имеет многих ловушек.

Синхронизирующийся доступ к совместно используемым данным, однако, хитер.

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

  1. , Что такое InterlockedIncrement?
  2. , Почему InterlockedIncrement должен существовать на уровне ассемблера?
  3. , Что переупорядочивает запись чтения?
  4. , Каково энергозависимое ключевое слово (в C++) и когда необходимо использовать его?
  5. , Что такое иерархия синхронизации?
  6. , Какова проблема ABA?
  7. , Что такое когерентность кэш-памяти?
  8. , Что такое барьер памяти?

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

11
ответ дан 27 November 2019 в 21:42
поделиться

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

существуют также мертвые блокировки , который является кодом A, ожидает кода B для выпуска ресурса Y, в то время как код B ожидает для выпуска ресурса X.

15
ответ дан 27 November 2019 в 21:42
поделиться

Вот большой ресурс о параллелизме, конкретно в Java: http://tech.puredanger.com/ Alex Miller перечисляет много других вопросов, с которыми можно встретиться при контакте с параллелизмом. Наиболее рекомендуемый :)

1
ответ дан 27 November 2019 в 21:42
поделиться
1
ответ дан 27 November 2019 в 21:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: