/ / Як реалізується ReactiveMongo, щоб він вважався не блокуючим? - масштабування, ігрові рамки, реактивне програмування, реактивнемоніго, ітерація

Як ReactiveMongo реалізується так, що він вважається неблокуючим? - scala, playframework, реактивне програмування, reactivemongo, ітерація

Читання документації про Play Framework та ReactiveMongo приводить мене до думки, що ReactiveMongo працює таким чином, що він використовує кілька потоків і ніколи не блокує.

Однак, схоже, що зв’язок від програми Play до сервера Mongo повинен був відбутися далі якась нитка десь. Як це реалізується? Посилання на вихідний код для Play, ReactiveMongo, Akka тощо також будуть дуже вдячні.

Play Framework містить деяку документацію про це на цій сторінці про басейни з нитками. Це починається:

Ігровий фреймворк знизу вгору є асинхронним веб-рамкою. Потоки обробляються асинхронно за допомогою ітерацій. Нитки пулів у Play налаштовані на використання менше ниток, ніж у традиційних веб-рамках, оскільки IO в play-core ніколи не блокується.

Потім він трохи розповідає про ReactiveMongo:

Найпоширеніше місце, яке типовий Playдодаток буде заблоковано, коли він спілкується з базою даних. На жаль, жодна з основних баз даних не забезпечує асинхронних драйверів баз даних для JVM, тому для більшості баз даних ваш єдиний варіант - використання блокування IO. А Помітний виняток з цього - ReactiveMongo, драйвер для MongoDB, який використовує бібліотеку Iteratee Play для спілкування з MongoDB.

Далі йде примітка про використання ф'ючерсів:

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

Аналогічна примітка є в документації Play на сторінці Поводження з асинхронними результатами:

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

Здається, документація говорить про цеReactiveMongo не блокує, тому вам не доведеться турбуватися про те, щоб з'їсти багато ниток у вашому потоці пулів. Але ReactiveMongo повинен спілкуватися з сервером Mongo десь.

Як ця комунікація реалізована так, що Mongo не використовує теми з пулу потоків потоків за замовчуванням Play?

Ще раз посилання на конкретні файли в Грати, ReactiveMongo, Аккатощо, буде дуже вдячним.

Відповіді:

11 за відповідь № 1

Так, дійсно, вам потрібно використовувати нитки для виконання будь-яких робіт, включаючи спілкування з базою даних. Що важливо як саме таке спілкування відбувається.

ReactiveMongo "не використовує нитки" в тому сенсі, який не використовує блокування вводу / виводу. Звичайні засоби вводу / виводу Java java.io.InputStream блокують; це означає, що читання з такого InputStream або писати до OutputStream блокує потік, поки "інша сторона" не надає потрібні дані або не буде готова прийняти їх. Для мережевого спілкування це означає, що потоки воля бути заблокованим.

Однак, надає Java NIO API яка підтримує неблокуючий і асинхронний I / O. Я не хочу зараз проникати в його деталі, але основна ідея, природно, полягає в тому, що незаблокований введення / вивід дозволяють не блокувати потоки, які потребують обміну деякими даними із зовнішнім світом: наприклад, ці потоки можуть опитуйте джерело даних, щоб перевірити, чи є якісь дані доступні, а якщо таких немає, вони повертаються до пулу потоків і можуть бути використані для інших завдань. Звичайно, внизу ці засоби надаються базовою ОС.

Точні деталі реалізації неблокуючих вводу-виводу зазвичай ховаються всередині бібліотек високого рівня Netty тому що це зовсім не приємно користуватися. Наприклад, Netty (саме бібліотека, яку використовує ReactiveMongo), забезпечує приємний асинхронний API, схожий на зворотний виклик, який дійсно простий у використанні, але також є досить потужним та виразним, що дозволяє створювати складні додатки, важкі для вводу / виводу, з високою пропускною здатністю.

Отже, ReactiveMongo використовує Netty для розмови з Монгосервер баз даних, і оскільки Netty є реалізацією асинхронної мережевої вводу-виводу, ReactiveMongo дійсно не потрібно тривалий час блокувати потоки.