Запис наборів даних у загальну пам’ять за допомогою PHP

Покроковий посібник з використання спільної пам'яті PHP як накопичувач

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

Це означає, що програма, написана мовою C, може обмінюватися інформацією з програмою, написаною іншою мовою, такою як Java™ або PHP. Вони можуть обмінюватися інформацією, якщо тільки здатні отримати та зрозуміти цю інформацію. Загальна пам'ять широко застосовується у реалізаціях, доступних більшості мов, тому отримання доступу має бути проблемою. Що стосується розуміння інформації, можна використовувати стандартний формат, такий як XML або JSON.

Загальна пам'ять є швидким способом обміну даними між процесами, головним чином тому, що після створення сегментів ядро ​​операційної системи не бере участі в процесі передачі даних. Подібні методи часто називають "міжпроцесною взаємодією" (interprocess communication - IPC). До інших методів IPC входять конвеєри, черги повідомлень, RPC і сокети. Такий швидкий і надійний спосіб обміну даними між додатками неоціненний при роботі з екосистемою додатків, яким потрібно спілкуватися один з одним. Звичайний метод використання баз даних для обміну інформацією між програмами часто призводить до повільної обробкизапитів і навіть блокування введення-виведення залежно від розміру екосистеми. Працюючи із загальною пам'яттю операції вводу-вывода, що уповільнюють процес, відсутні.

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

Загальна пам'ять та PHP

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

Створення сегментів

Функції спільної пам'яті подібні до функцій керування файлами, тільки замість потоків ви працюєте з ідентифікаторами доступу до спільної пам'яті. Першим прикладом є функція shmop_open , яка дозволяє відкрити існуючий або створити новий сегмент. Ця функція дуже схожа на класичну функцію fopen , яка відкриває потоки для маніпуляції файлами, повертаючи ресурс, доступний для використання іншими функціями, що виконують операції читання або запису цього відкритого потоку. Розглянемо функцію shmop_open, наведену в лістингу 1.

Лістинг 1. Функція shmop_open

Перший параметр - system ID. Це число, що визначає сегмент загальної пам'яті системи. Другий параметр - режим доступу, який дуже схожий на режим доступу функції fopen. Доступ до сегмента можна отримати чотирмаспособами:

  • режим "а" дозволяє звертатися до сегменту лише для читання;
  • режим "w" дозволяє звертатися до сегменту для читання та запису;
  • в режимі "c" створюється новий сегмент, а якщо він вже існує, робиться спроба відкрити його для читання та запису;
  • режим "n" створює новий сегмент, а якщо він уже існує, видається повідомлення про помилку.

Третій параметр – роздільна здатність для сегмента. Тут потрібно вказати вісімкове число.

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

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

Запис у сегменти

Для запису даних у блок спільної пам'яті скористайтеся функцією shmop_write . Вона дуже проста у застосуванні та приймає всього три параметри. Див. листинг 2.

Лістинг 2. Застосування функції shmop_write для запису до блоку спільної пам'яті

Вона схожа на функцію fwrite , яка приймає два параметри: відкритий ресурс потоку, що повертається функцією fopen і дані, що підлягають запису. Функція shmop_write робить те саме.

Читання із сегментів

Читання із сегментів загальної пам'яті – проста процедура. Достатньо відкрити сегмент і скористатися функцією shmop_read. Вона приймає кілька параметрів та працює аналогічно функції fread. У лістингу 3 наведено приклад читання вмісту файлу PHP.

Лістинг 3. Використання функціїshmop_read для читання вмісту файлу

Читання вмісту загальної пам'яті виконується аналогічно, як показано в лістингу 4.

Лістинг 4. Читання вмісту сегмента пам'яті

Зверніть увагу на параметри. Функція shmop_read приймає ідентифікатор, повернутий функцією shmop_open , який нам вже знайомий, та два інші параметри. Другий параметр - місце, з якого потрібно почати читання сегмента; а третій - кількість байтів, яку потрібно рахувати. Другий параметр завжди може бути 0, початком даних, зате третій може викликати проблему, оскільки ми можемо не знати, скільки байтів хочемо рахувати.

Це дуже схоже на поведінку функції fread, яка приймає два параметри: відкритий ресурс потоку, що повертається функцією fopen, і кількість байтів, які потрібно рахувати з цього потоку. Щоб прочитати файл у всій його повноті, використовуйте функцію filesize , яка повертає кількість байтів у файлі.

На щастя, при роботі з сегментами загальної пам'яті функція shmop_size, подібно до функції filesize, повертає розмір сегмента в байтах. (Див. лістинг 5).

Лістинг 5. Функція shmop_size повертає розмір сегмента в байтах

Видалення сегменту

Ми знаємо, як відкривати, записувати та зчитувати сегменти спільної пам'яті. Для завершення нашого класу з CRUD залишилося лише дізнатися, як видаляти сегменти. Цю задачу можна легко вирішити за допомогою функції shmop_delete , яка потребує лише одного параметра: ідентифікатор сегмента загальної пам'яті, який ми хочемо видалити.

Лістинг 6. Функція shmop_delete позначає сегмент видалення

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

Закриття сегменту

При відкритті сегменту спільної пам'яті ви приєднуєтеся до нього. Приєднавшись до сегменту, можна записувати дані і зчитувати їх із нього, але коли робота закінчена, потрібно від'єднатися від сегмента. Це робиться за допомогою функції shmop_close, як показано в лістингу 7.

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

Лістинг 7. Використання функції shmop_close для від'єднання від сегмента

Використання спільної пам'яті як накопичувач

Маючи базові знання в області загальної пам'яті та освоївши основні операції CRUD над сегментами загальної пам'яті, можна приступати до практичного застосування цих знань. Загальну пам'ять можна використовувати як унікальну альтернативу накопичувачу, яка пропонує такі переваги, як швидкі операції читання/запису та взаємодія процесів. Для Web-програми це означає:

  • буферну пам'ять (зберігання запитів до бази даних, даних Web-сервісів, зовнішніх даних);
  • пам'ять сеансів;
  • обмін даними між програмами.

Перш ніж продовжити, я хотів би представити невелику бібліотеку SimpleSHM. Це компактний рівень абстракції для роботи із загальною пам'яттю в PHP, що дозволяє легко маніпулювати сегментами із застосуванням об'єктно-орієнтованого підходу. Ця бібліотека допомагає створювати набагато чистіший код під час написання невеликих програм, які використовують спільну пам'ять для зберігання даних. Для початку роботи з SimpleSHM завантажте tarball-файл зі сторінкиGitHub.

Існує три види операцій: читання, запис та видалення. Просте створення екземпляра об'єкта класу забезпечить відкриття сегмента пам'яті. Основні моменти відображені у лістингу 8.

Лістинг 8. Основи використання SimpleSHM

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

Лістинг 9. Відкриття заданого сегмента

Магічний метод __destructor дбає про виклик функції shmop_close по відношенню до сегмента, щоб відключити об'єкт і від'єднати його від сегмента. Назвемо це "SimpleSHM 101". Тепер скористаємося ним для вищої мети: використання спільної пам'яті як накопичувач. Для зберігання наборів даних потрібна серіалізація, оскільки в пам'яті не можна зберігати масиви або об'єкти. Тут для серіалізації використовується JSON, але підійде будь-який інший метод, наприклад, XML або вбудовані функції серіалізації PHP. Приклад наведено у лістингу 10.

Лістинг 10. Використання загальної пам'яті як накопичувача

Ми успішно перетворили масив у рядок JSON, зберегли його в блоці загальної пам'яті, вважали, перетворили рядок JSON назад на масив і відобразили його. Все це здається тривіальним, але тільки уявіть, які можливості відкриває цей фрагмент. Його можна використовувати для зберігання результатів запитів до Web-сервісу, баз даних або навіть як буфер процесора текстових шаблонів. Запис та читання з пам'яті забезпечить набагато більшу продуктивність, ніж запис та читання з диска.

Цей метод зберігання корисний нетільки для використання як буфер, але й для обміну даними між додатками, якщо ці дані зберігаються у форматі, зрозумілому обом додаткам. Не можна недооцінювати можливості спільної пам'яті у Web-додатках. Існує безліч різних способів ефективної реалізації такого зберігання, і єдине обмеження тут – талант та майстерність програміста.

Висновок

Що далі?

Ми вказали деякі спільні завдання, для вирішення яких ідеально підходить спільна пам'ять, такі як кешування, спільне використання сеансу та обмін даними між програмами. Це введення в роботу із загальною пам'яттю відкриває перед читачем можливості дослідження набагато більш елегантних рішень типових завдань. Не соромтеся розширювати поточну реалізацію SimpleSHM відповідно до своїх потреб та вносити ці зміни до проекту.

Ресурси для скачування

Схожі теми

  • Оригінал статті: Store datasets directly in shared memory with PHP.
  • Книга Майкла Керріска Інтерфейс програмування Linux містить чудові розділи про міжпроцесну взаємодію, а розділи 45-48 присвячені IPC System V.
  • У статті Дейва Маршалла IPC: загальна пам'ять описаний цікавий та прагматичний підхід до функцій спільної пам'яті мовою Сі.
  • Книга Річарда Стівенса Програмування мережі UNIX містить відмінний технічний матеріал та опис кількох реалізацій мовою C. Ознайомтеся з витримкою з розділу цієї книги.
  • Слідкуйте за developerWorks у Твіттері.

Коментарі