Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
PHP на примерах (2 издание). Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В. Объектно-ориентированное программирование на PHP. Авторы: Кузнецов М.В., Симдянов И.В. MySQL 5. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. PHP Puzzles. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Не выгружать скрипт из памяти
 
 автор: Eugene77   (08.06.2012 в 18:36)   письмо автору
 
 

Можно ли не выгружать скрипт из памяти компьютера?

Проблема в том, что скрипт производит арифметические вычисления пользуясь массивом, который всякий раз загружает из MySQL.
Так вот на unserialize() этого массива уходит слишком уж много времени.

  Ответить  
 
 автор: cheops   (08.06.2012 в 19:27)   письмо автору
 
   для: Eugene77   (08.06.2012 в 18:36)
 

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

Можно попробовать Кэшировать массив в виде PHP-файла с уже развернутым массивом, который подключайте при помощи require_once(), предварительно проверив его существование. Раз в час уничтожайте его при помощи cron-задания, если файл не существует, запрашивайте базу данных и восстанавливайте кэш-файл.

  Ответить  
 
 автор: Eugene77   (09.06.2012 в 05:38)   письмо автору
 
   для: cheops   (08.06.2012 в 19:27)
 

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

>
>Можно попробовать Кэшировать массив в виде PHP-файла с уже развернутым массивом,
Вот это интересная идея. Только дело осложняется тем, что массив при каждом вызове скрипта меняется. 90% остаётся неизменных элементов, но около 10% элементов массива скрипт изменяет.

Массив является свойством экземпляра класса, как его кэшировать в виде развёрутого файла не вполне ясно.

  Ответить  
 
 автор: cheops   (09.06.2012 в 07:46)   письмо автору
 
   для: Eugene77   (09.06.2012 в 05:38)
 

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

>Вот это интересная идея. Только дело осложняется тем, что массив при каждом вызове скрипта
>меняется. 90% остаётся неизменных элементов, но около 10% элементов массива скрипт
>изменяет.
А насколько велик полный массив (может его как-то можно порезать)?

  Ответить  
 
 автор: Eugene77   (09.06.2012 в 10:12)   письмо автору
 
   для: cheops   (09.06.2012 в 07:46)
 

>Параллельности полно еще до начала ситуации на уровне Web-сервера и обслуживания клиентов. Если вы начинаете держать в памяти кусок данных для следующих скриптов, которые могут обращаться от двух независимых клиентов одновременно, вам необходимо обеспечивать диспетчеризацию этого куска памяти (что скорости обработки запроса никак не добавляет, да и не так просто, придется сайт на C/C++ писать, да еще и подстраиваться под особенности текущей операционной системы).
Диспетчеризация уже сделана.
Скрипт перед запуском проверяет все-ли необходимые данные записаны в базу, если нет, то просто завершается через exit().
>

>А насколько велик полный массив (может его как-то можно порезать)?
Массив в сериализованном виде занимает около 20767 байт.

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

  Ответить  
 
 автор: cheops   (09.06.2012 в 13:58)   письмо автору
 
   для: Eugene77   (09.06.2012 в 10:12)
 

>Диспетчеризация уже сделана.
>Скрипт перед запуском проверяет все-ли необходимые данные записаны в базу, если нет, то
>просто завершается через exit().
Имеется в виду на системном уровне, диспетчеризация доступа параллельных потоков к одному ресурсу... Не трогая C-кода, хотя бы на уровне расширения этого из PHP не реализовать - у него даже зачатков параллелизма - это одно из положений, за которое его всегда критикуют. Без внешней же памяти, вам массив не передать.

>Порезать его непонятно как, так как он в качестве элементов содержит другие массивы. Которые
>в свою очередь тоже имеют вложенность, всего не более 5 уровней, но изменяющиеся данные
>вкраплены везде по чуть-чуть.
Исходный массив для всех одинаковый, или каждый пользователь имеет свой уникальный массив? Нельзя ли тут как-то сессию задействовать?

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

  Ответить  
 
 автор: Eugene77   (10.06.2012 в 06:54)   письмо автору
 
   для: cheops   (09.06.2012 в 13:58)
 

Имеется в виду на системном уровне, диспетчеризация доступа параллельных потоков к одному ресурсу... Не трогая C-кода, хотя бы на уровне расширения этого из PHP не реализовать - у него даже зачатков параллелизма - это одно из положений, за которое его всегда критикуют. Без внешней же памяти, вам массив не передать.

Не такая, конечно, крутая диспетчеризация, как вы пишете, но своя диспетчеризация у меня есть, без неё задача не решалась.
Несколько процессов (Не на PHP) следят за внешними событиями.
Когда происходит событие вызывается PHP скрипт его обработки, но скрипт может обработать ситуацию только если события произошли во всех процессах (примерно одновременно).
Поэтому скрипт пишет информацию о полученном событии в базу, а после этого проверяет наличие записей с той же временной меткой о событиях зафиксированных другими процессами, если записи присутствуют не все, то скрипт просто завершается.
Если скрипт был вызван последним, и нашёл полный комплект записей с информацией обо всех событиях от всех процессов, то он грузит свой массив из базы и делает расчёты, возвращает результат обратившемуся к нему процессу.


Исходный массив для всех одинаковый, или каждый пользователь имеет свой уникальный массив? Нельзя ли тут как-то сессию задействовать?
Исходный массив одинаковый, если пользоатели обратились к нему с одинаковыми GET-параметрами и не все. Когда обращается последний пользователь(из списка с одинаковыми GET параметрами), производятся вычисления и массив изменяется. Сессию задействовать, думаю, можно. Только в чём будет преимущество?
>
>PS Вообще ошибка в хранении сериализованного массива в базе данных - так вы моментально убиваете преимущества СУБД. В этом подводный камень скрещивания двух похожих, но принципиально перпендикулярных друг к другу технологий - очень много нужно приложить усилий на границе, либо вам, либо серверу.
В чём конкретно состоит разница в объёме усилий? Долго извлекать длинную запись из таблицы? Таблица невелика, обращение к ней по первичному ключу...

  Ответить  
 
 автор: cheops   (10.06.2012 в 11:50)   письмо автору
 
   для: Eugene77   (10.06.2012 в 06:54)
 

>Исходный массив одинаковый, если пользоатели обратились к нему с одинаковыми GET-
>параметрами и не все. Когда обращается последний пользователь(из списка с одинаковыми
>GET параметрами), производятся вычисления и массив изменяется. Сессию задействовать,
>думаю, можно. Только в чём будет преимущество?
Зависит от данных, однако, если в сессии уже есть массив или данные, а это всегда можно проверить, то не потребуется новый запрос к базе данных. Чем дольше сессия - тем больше выгода, таская за собой сессию часами посетитель не делает лишних запросов.

>В чём конкретно состоит разница в объёме усилий? Долго извлекать длинную запись из
>таблицы? Таблица невелика, обращение к ней по первичному ключу...
Чтобы задействовать возможности СУБД в частности по поиску и покрыть накладные расходы, которая СУБД обязательно производит за счет своей сложной организации, вам нужно преобразовывать объекты или сложные массивы в реляционные структуры - это довольно трудоемкий процесс, который довольно сложно автоматизировать. При автоматизации легко построить неэффективную СУБД, которая не позволит задействовать индексацию, кэши и прочие возможности СУБД по ускорению работы. Поэтому, как правило, получается либо мощная база данных, либо мощная объектная модель. Чтобы соединить их, оставив и то и то, нужно проделать титаническую работу по программированию соответствующего интерфейса (что скорости и надежности не добавляет).

  Ответить  
 
 автор: Eugene77   (10.06.2012 в 13:23)   письмо автору
 
   для: cheops   (10.06.2012 в 11:50)
 

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

  Ответить  
 
 автор: cheops   (10.06.2012 в 16:21)   письмо автору
 
   для: Eugene77   (10.06.2012 в 13:23)
 

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

  Ответить  
 
 автор: Desh   (10.06.2012 в 10:06)   письмо автору
 
   для: Eugene77   (08.06.2012 в 18:36)
 

Попробуйте ипользовать разделяемую память. Насколько я понял, она идеально подойдёт в Вашем случае.

Подробнее можете прочитать по ссылкам:
http://php.net/manual/ru/book.shmop.php
http://phpclub.ru/detail/article/shared_memory

  Ответить  
 
 автор: Eugene77   (10.06.2012 в 13:19)   письмо автору
 
   для: Desh   (10.06.2012 в 10:06)
 

>Попробуйте ипользовать разделяемую память. Насколько я понял, она идеально подойдёт

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

  Ответить  
 
 автор: Desh   (11.06.2012 в 00:05)   письмо автору
 
   для: Eugene77   (10.06.2012 в 13:19)
 

Пробовал и активно использую - очень хорошая штука;)

Вы же из памяти производите только выборки (ну иногда добавляете/обновляете информацию) как я понимаю? В случае выборки одновременный доступ к памяти никак не повливает на данные (не испортит их). Это как из БД (пусть будет MySQL) делять SELECT-запрос - их же могут делать одновременно несколько подпрограмм и ничто не будет испорченно:) Только разделяемая память в десятки раз быстрее и проще:)

Если вы хотите обновить там данные и хотите, чтобы в тот момент никто не мог эти данные получить (чтобы не забрать случайно старые данные до обновления), то пользуйтесь семафорами. А в программе, которая берёт данные из памяти циклически обрабатывайте получение данные. К примеру, если установлен семафор, то попробовать получить данные ещё раз через n миллисекунд.

Надеюсь правильно понял Ваш вопрос.

  Ответить  
 
 автор: Eugene77   (11.06.2012 в 17:50)   письмо автору
 
   для: Desh   (11.06.2012 в 00:05)
 

Только разделяемая память в десятки раз быстрее и проще

Это и всё остальное, что вы пишете, очень интересно.

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

Я почему-то впервые сталкиваюсь с обсуждением данной темы.
Было бы интересно послушать мнение Хеопса и др. старожилов. Например, классы в РНР широко используются, а ошибок в них ещё много. К счастью, ошибки связанные с объектами быстро показывают себя. А вот с разделяемой памятью может получиться наоборот: при малой нагрузке - работает, а при значительной нагрузке даст сбой.

Вы пробовали стресс-тесты программ с разделяемой памятью делать?

  Ответить  
 
 автор: Desh   (11.06.2012 в 22:43)   письмо автору
 
   для: Eugene77   (11.06.2012 в 17:50)
 

Я её использую в небольшом стартапе. Пока никаких сбоев и т.п. замечено не было за более 7 месяцев. Да и не должно быть, т.к. это очень простой метод в реализации и очень странно почему мало распространён. В нём, правда, нельзя шибко много данных хранить (128мб по-умолчанию уставновлено в PHP, но надо ещё настраивать настройки в самой ОС, т.к. там скорее всего ограничено 8мб (так было в моём случае)).

Быстрее просто потому, что разделяемая память - это участок в оперативной памяти ПК в то время как таблица в БД (в зависимости от типа БД) - это всёго лишь файлик на жёстком диске. А оперативная память, как Вы понимаете, гораздо быстрее.

Тут попросту неоткуда возникать ошибкам, серъёзно:)

В любом случае дело, конечно, за Вами, как решить Вашу задачу. Я не пиарщик этого метода и мне за это даже не приплачивают;)

  Ответить  
 
 автор: Eugene77   (12.06.2012 в 05:50)   письмо автору
 
   для: Desh   (11.06.2012 в 22:43)
 

А что можно сделть?:
а) закинуть в разделяемую память сериализоанный массив
б) записать туда массив в бинарном виде
в) записать туда фотографию всего скрипта целиком, со значениями переменных, как есть?

Настройки ОС мне доступны (комп. у меня дома)

  Ответить  
 
 автор: Desh   (12.06.2012 в 14:57)   письмо автору
 
   для: Eugene77   (12.06.2012 в 05:50)
 

В Вашем случае сериализованный массив.

Если записывать просто сами элементы массива, то больше 100-1000 штук (в зависимости от настроек) Вам вряд ли система позволит добавить. А вот записать строку позволит без проблем.

Т.е., к примеру, получается у Вас есть массив в сериализованном виде. Создаёте сектор в разделяемой памяти (как по ссылкам выше, которые я публиковал).

Получается что-то вроде этого (здесь старый формат со старых версий PHP, но Вы их легко замените на новый):
$MEMSIZE = 1024 * 1024;    
// Ключ сектора
$SHMKEY = 3;
$shm_id = shm_attach($SHMKEY, $MEMSIZE);


Затем вставляете нужный массив. В старом формате это выглядит так:

$var = shm_put_var($shm_id, 0, $arr);

где $arr - сериализованная строка Вашего массива, а 0 - номер ячейки куда добавлять данные (от 0 до n).

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

$key = shm_get_var($shm_id, 0);

где 0 - номер ячейки с данными (в коде Выше мы добавляли строку в ячейку под этим номером).

  Ответить  
 
 автор: confirm   (12.06.2012 в 16:27)   письмо автору
 
   для: Desh   (12.06.2012 в 14:57)
 

Лучше JSON использовать вместо сеарелизации, это и короче запись, и быстрее преобразование.

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования