Різниця між споживачем / виробником та спостерігачем / спостережуваним


16

Я працюю над розробкою програми, яка складається з трьох частин:

  • єдиний потік, який спостерігає за певними подіями (створення файлів, зовнішні запити тощо)
  • N робочих ниток, які реагують на ці події, обробляючи їх (кожен працівник обробляє та споживає одну подію, і обробка може зайняти різний час)
  • контролер, який керує цими потоками та виконує обробку помилок (перезапуск потоків, реєстрація результатів)

Хоча це досить елементарно і не важко здійснити, мені цікаво, який би це був "правильний" спосіб зробити це (у цьому конкретному випадку на Java, але також високо оцінені відповіді на більш високі абстракції). На думку приходять дві стратегії:

  • Спостерігач / Спостереження: контрольну нитку спостерігає контролер. У випадку події контролер повідомляється і може призначити нове завдання вільному потоку з кешованого пулу ниток багаторазового використання (або чекати та кешувати завдання в черзі FIFO, якщо всі потоки зараз зайняті). Робочі потоки реалізують Callable і повертають успішно з результатом (або булевим значенням), або повертаються з помилкою, і в цьому випадку контролер може вирішити, що робити (залежно від характеру помилки, що трапилася).

  • Виробник / Споживач : Нитка перегляду поділяє BlockingQueue з контролером (чергою подій), а контролер ділиться двома з усіма працівниками (черга завдань та черга результатів). У випадку події поток спостереження ставить об’єкт завдання у чергу подій. Контролер приймає нові завдання з черги подій, переглядає їх і ставить їх у чергу завдань. Кожен працівник чекає нових завдань і приймає / споживає їх із черги завдань (першим приходить перший сервіс, керується самою чергою), переносячи результати або помилки назад у чергу-результат. Нарешті, контролер може отримати результати з черги результатів і вжити помилок у разі помилок.

Кінцеві результати обох підходів схожі, але кожен з них має невеликі відмінності:

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

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

Який був би найбільш підходящий підхід у цій ситуації і чому? Мені складно знайти відповіді на це запитання в Інтернеті, оскільки більшість прикладів стосуються лише явних випадків, таких як оновлення багатьох вікон на нове значення у випадку Observer або обробка кількома споживачами та виробниками. Будь-який вклад дуже вдячний.

Відповіді:


10

Ви досить близькі до відповіді на власне запитання. :)

У шаблоні спостереження / спостереження (зверніть увагу на фліп) слід пам’ятати про три речі:

  1. Як правило, повідомлення про зміну, тобто "корисний вантаж", спостерігається.
  2. Спостережуване існує .
  3. Спостерігачі повинні бути відомі існуючим спостерігаючим (інакше їм немає за чим спостерігати).

Поєднуючи ці моменти, мається на увазі те, що спостережуваний знає, які його компоненти нижче, тобто спостерігачі. Потік даних по суті визначається спостережуваним - спостерігачі просто "живуть і вмирають" від того, що спостерігають.

У моделі виробник / споживач ви отримуєте дуже різну взаємодію:

  1. Як правило, корисне навантаження існує незалежно від виробника, відповідального за його виробництво.
  2. Виробники не знають, як і коли активні споживачі.
  3. Споживачі не повинні знати про виробника корисного навантаження.

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

Інша не надто тонка відмінність полягає в тому, що декілька спостерігачів на одному і тому ж спостережуваному рівні зазвичай отримують однаковий корисний вантаж (якщо не відбувається нетрадиційна реалізація), тоді як декілька споживачів одного і того ж виробника не можуть. Це залежить від того, чи є посередник підходом до черги чи теми. Перший передає інше повідомлення для кожного споживача, тоді як останній забезпечує (або намагається), що всі споживачі обробляють на основі повідомлення.

Щоб встановити їх у вашу заявку:

  • У шаблоні спостереження / спостерігача, коли ініціалізація потоку спостереження повинна знати, як повідомити контролер. Як спостерігач, контролер, ймовірно, чекає сповіщення від спостерігаючої нитки, перш ніж він дозволить потокам обробляти зміни.
  • У шаблоні «Виробник / Споживач» ваша нитка перегляду повинна знати лише наявність черги подій і взаємодіє виключно з нею. Як споживач, контролер потім опитує чергу подій, і як тільки він отримує нову корисну навантаження, він дозволяє потокам обробляти його.

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


2
Дякую за детальну відповідь. На жаль, я не можу подати заявку через відсутність репутації, тому я позначив це як рішення. Тимчасова незалежність між обома частинами, про які ви згадали, - щось позитивне, про яке я до цього часу не думав. Черги можуть керувати короткими спалахами багатьох подій з довгими паузами між набагато кращими, ніж прямі дії після того, як спостерігаються події (якщо максимальний кількість потоків фіксований і відносно низький). Кількість ниток також можна динамічно збільшувати / зменшувати залежно від поточного кількості елементів черги.
користувач183536

@ user183536 Немає проблем, рада допомогти! :)
hjk
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.