Helpers - компьютеры, интернет, программирование

Поражает ли "блокирующая" очередь саму цель многопоточности?

ArrayBlockingQueue блокирует поток-производитель, если очередь заполнена, и блокирует поток-получатель, если очередь пуста.

Разве эта концепция блокировки не противоречит самой идее многопоточности? если у меня есть «основной» поток и, допустим, я хочу делегировать все действия «Ведение журнала» другому потоку. Итак, в основном внутри моего основного потока я создаю Runnable для регистрации вывода и помещаю Runnable в ArrayBlockingQueue. Вся цель этого - немедленно вернуть «основной» поток, не тратя время на дорогостоящую операцию записи в журнал.

Но если очередь заполнена, основной поток будет заблокирован и будет ждать, пока не освободится место. Так как это нам помогает?


  • Конфликт потоков, их нехватка и небезопасный параллельный доступ - все это проблемы, которые необходимо решать при многопоточности. Потоки плохо взаимодействуют с общими ресурсами, если это явно не указано. 05.07.2013
  • Вы учитываете только тот случай, когда очередь заполнена. В любом другом случае поток не будет заблокирован. 05.07.2013
  • @Makoto О чем ты? Это не имеет отношения к вопросу. Кстати, BlockingQueues 'потокобезопасны ... См. docs.oracle.com/javase/6/docs/api/java/util/concurrent/ 05.07.2013

Ответы:


1

Думаю, это дизайнерское решение. Если он выбрал режим блокировки, ArrayBlockingQueue предоставит ему метод put. Если разработчику не нужен режим блокировки, у ArrayBlockingQueue есть метод offer, который вернет false, когда очередь заполнена, но затем ему нужно решить, что делать с повторным событием регистрации.

05.07.2013

2

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

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

05.07.2013

3

В вашем примере я бы рассмотрел блокировку как функцию: она предотвращает OutOfMemoryError.

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

С другой стороны, если нагрузка сбалансирована, очередь не блокируется.

05.07.2013

4

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

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

Это позволит вызывающему коду решить, как он хочет обрабатывать полную очередь.

Если порядок выполнения при обработке элементов из очереди не важен, я рекомендую использовать пул потоков (известный как ExecutorService в Java).

05.07.2013

5

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

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

Напротив, представьте себе блокирующую очередь с нулевым объемом сообщений. Таким образом, чтобы система работала вообще, вам нужно будет найти способ гарантировать, что регистратор всегда гарантированно сможет получить сообщение из основного потока. Это CSP. Это может означать, что в вашем гипотетическом потоке регистратора у вас должна быть буферизация, определяемая приложением (в отличие от лучшего предположения разработчика фреймворка о том, насколько глубоким должен быть FIFO), подсистема быстрого ввода-вывода, проверки на соответствие, способы решения отставание и т. д. Короче говоря, это не позволяет вам уйти от ответственности, вы вынуждены учитывать все аспекты производительности вашей системы.

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

05.07.2013

6

Похоже, у вас есть общее представление о том, почему вы должны использовать что-то вроде ArrayBlockingQueue для разговора между потоками.

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

Однако для вашего конкретного случая использования я бы использовал ExecutorService вместо прямого чтения / записи очередей, что создает пул фоновых рабочих потоков:

http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html

pool = Executors.newFixedThreadPool(poolSize);
pool.submit(myRunnable);
05.07.2013
  • Использование исполнителя с несколькими потоками не приведет к упорядочиванию при обработке элементов очереди. Это не было требованием к вопросу, но стоит упомянуть. 05.07.2013
  • Верно - хотя, если у вас только один поток (poolSize = 1), он эквивалентен. 05.07.2013
  • Хорошая точка зрения. Было бы здорово получить результат от исполняемого, поставить его в очередь в какой-нибудь диспетчер обработки приоритетных событий, а затем уведомить слушателей, когда будет выполнен следующий элемент. Таким образом, вы также можете использовать преимущества нескольких ядер. Опять же, это предполагает, что порядок важен. И что эта дополнительная синхронизация и упорядочение не замедляют работу до точки, при которой использование одного потока выполняется быстрее. 05.07.2013
  • Извините, но если я использую службу исполнителя, мне не нужно помещать и забирать элементы в / из очереди внутри моего метода run ()? можешь немного уточнить? 05.07.2013
  • Правильно, ExecutorService абстрагирует цикл while (not finished) { wait for job on queue; run job; } фонового потока. Вы просто submit ваш Runnable. 05.07.2013

  • 7

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

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

    05.07.2013

    8

    Вы должны выбрать, что делать, когда очередь заполнена. В случае очереди Array Blocking этот выбор - подождать.

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

    Вы должны пойти на компромисс.

    05.07.2013
  • Класс BlockingQueue уже выполняет выброс при заполнении, если хотите. Просто используйте .offer(). 05.07.2013
  • @BrunoReis Спасибо, я взглянул на API и пропустил! 05.07.2013
  • Новые материалы

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

    Использование машинного обучения для диагностики болезни Альцгеймера, часть 4
    Маркеры семантической согласованности для ранней диагностики болезни Альцгеймера (arXiv) Автор: Давиде Колла , Маттео Дельсанто , Марко Агосто , Бенедетто Витиелло , Даниэле Паоло Радичони..

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

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

    Создание простого слайдера изображений с помощью JavaScript
    Узнайте, как создать базовый слайдер изображений с помощью HTML, CSS и JavaScript. Введение В этом уроке мы создадим удобный слайдер изображений, используя JavaScript, HTML и CSS. Ползунок..

    Создание базы данных с помощью супергероя «Python»
    В этом посте мы узнаем, как создать «базу данных SQLite с помощью модуля python sqlite3, создав простую функцию входа и регистрации. Готовы ли вы к этому путешествию? Если да , давайте приступим..

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