PHP опкод, генерируемый PHP-движком, сильно зависит от способа, которым вы пишете ваш код, не только в отношении количества операторов для выполнения задачи. Кратко, это имеет очень большое значение, и я думаю, это очевидно для вас.
Менее очевидно является то, что даже синтаксис кода может полностью изменить генерируемый опкод, вызывая очень много накладных расходов на CPU для выполнения точно той же кодовой последовательности.
В последние несколько лет моя SaaS-продукция сильно выросла, и это дало мне возможность искать все глубже и глубже оптимизационных техник для максимально эффективного выполнения моей рабочей нагрузки.
Результаты, которые я видел, были впечатляющими и сильно помогли мне в解锁 свободного капитала для продолжения развития моей SaaS-пути.
В настоящее время PHP-процесс в моей SaaS-продукции обрабатывает более 1,2 миллиардов (с “б”) данных каждый день на машине с 2vCPU и 8GB оперативки. Я использую AWS автоматическое масштабирование, чтобы иметь больше гибкости в случае непредсказуемых скачков, но это редко добавляет вторую машину (одну/две vez a week).
Перейдем к теме статьи. Я думаю, что это очень интересно вам.
Что такое PHP Opcode?
PHP опкод означает оператор кода, и он относится к низкоуровневым инструкциям, которые выполняются PHP-движком после того, как PHP-исходный код, который вы пишете, был компилирован.
В PHP компиляция кода происходит во время выполнения: в основном, первый раз, когда ваш код берется PHP-движком, он будет компилирован в этот машинно-friendly код, кэширован (таким образом, движок не компилирует тот же код снова), и затем выполнен.
Простое представление процесса:
Кэширование операций PHP
Кэширование операций PHP позволяет сохранить три шага в процессе выполнения кода: парсинг исходного PHP кода, токенизация и компиляция.
После первого создания операций, они сохраняются в памяти, чтобы их можно было использовать в последующих запросах. Это уменьшает необходимость PHP движка перекомпилировать тот же PHP код каждый раз, когда он выполняется, сэкономив много ЦП и памяти.
Самым распространенным кэшем операций в PHP является OPCache, который включен по умолчанию с PHP 5.5 и до последних версий. Он очень эффективен и широко поддерживается.
Кэширование предкомпилированного скриптового байткода требует сброса кэша после каждого развертывания. Это because если измененные файлы содержат версию байткода в кэше, PHP будет выполнять старую версию кода, пока вы не очистите кэш операций, поэтому новый код будет компилирован снова, генерируя новую запись кэша.
Как исследовать операции PHP
Чтобы понять, как различные синтаксисы могут影响 скриптовый операции, нам нужно найти способ за Grabbing the compiled code generated by the PHP engine.
Имеется два способа получения операций.
Свойства Native Functions OPCache
Если расширение OPCache включено на вашей машине, вы можете использовать его native functions, чтобы получить операции определенного PHP файла:
// Force compilation of a script
opcache_compile_file(__DIR__.'/yourscript.php');
// Get OPcache status
$status = opcache_get_status();
// Inspect the script's entry in the cache
print_r($status['scripts'][__DIR__.'/yourscript.php']);
VLD (Vulcan Logic Disassembler) PHP Extension
VLD — это популярное расширение PHP, которое дезассемблирует компилированный PHP код и выводит опкод. Это мощное средство для понимания того, как PHP интерпретирует и выполняет ваш код. После установки вы можете запустить PHP скрипт с включенным VLD, используя команду php
с опциями -d
:
php -d vld.active=1 -d vld.execute=0 yourscript.php
Выходные данные будут включать детальную информацию о компилированном опкоде, включая каждую операцию, ее соответствующую строку кода и другие данные.
Использование 3v4l (акроним для EVAL)
3v4l является очень полезным онлайн- инструментом, который позволяет вам просмотреть опкод, генерируемый PHP кодом, который вы вставляете в редактор. Fundamentally, это PHP сервер с установленным VLD, который может захватить выход VLD и показать опкод в браузере.
Being free, we will use this online tool for further analyses.
Как Generate Efficient PHP Opcode
3v4l perfect for understanding how the code syntax we use can influence the resulting PHP opcode in a good or bad way. Let’s start pasting the code below into 3v4l. Keep the configuration “all supported versions” and click on “eval”.
namespace App;
strlen('ciao');
After executing the code, a tab menu will appear at the bottom. Navigate to the VLD tab to visualize the corresponding Opcode.
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
5 0 E > INIT_NS_FCALL_BY_NAME 'App%5CSpace%5Cstrlen'
1 SEND_VAL_EX 'ciao'
2 DO_FCALL 0
3 > RETURN 1
Первая операция – INIT_NS_FCALL_BY_NAME
. Интерпретатор строит имя функции с использованием пространства имён текущего файла, но она не существует в пространстве имён App\Example
– так как это работает?
Интерпретатор проверит, существует ли функция в текущем пространстве имён. Если нет, он попробует вызвать соответствующую встроенную функцию.
Здесь у нас есть возможность сообщить интерпретатору, чтобы он обошёл это двойное проверки и сразу же выполнил встроенную функцию.
Попробуйте добавить backslash (\
) перед strlen
и нажмите “eval”:
namespace App;
\strlen('ciao');
Вкладка VLD теперь показывает опкод с одним заявлением.
line #* E I O op fetch ext return operands
------------------------------------------------------------------------------------- 5 0 E > > RETURN 1
Поскольку вы указали точное местоположение функции, ей не требуется рассматривать никакогоallback.
Если вы не хотите использовать backslash, вы можете импортировать функцию, как любую другую класс из корневого пространства имён:
namespace App;
use function strlen;
strlen('ciao');
Использование Автоматических Опкодных Optimizations
Также существует много внутренних автоматизмов PHP-engine для генерации опкода, оценивая статические выражения заранее. Это было одним из самых важных причин большого улучшения производительности PHP с 7.x версии.
Знание этих динамик может помочь вам снизить потребление ресурсов и снизить затраты. Когда я сделал эту исследование, я стал использовать этиtricks во всем коде.
Покажу вам пример с использованием PHP-констант. Запустите этот скрипт в 3v4l:
namespace App;
if (PHP_OS === 'Linux') {
echo "Linux";
}
Посмотрите на первые две строки PHP opcode:
line #* E I O op fetch ext return operands
------------------------------------------------------------------------------------- 5 0 E > FETCH_CONSTANT ~0 'App%5CPHP_OS' 1 IS_IDENTICAL ~0, 'Linux' 2 > JMPZ ~1, ->4 6 3 > ECHO 'Linux' 7 4 > > RETURN 1
FETCH_CONSTANT
пытается получить значение PHP_OS
из текущего пространства имен и будет искать в глобальном пространстве имен, поскольку оно не существует здесь. Затем инструкция IS_IDENTICAL
выполняет оператор IF
.
Теперь попробуйте добавить обратную косую черту к константе:
namespace App;
if (\PHP_OS === 'Linux') {
echo "Linux";
}
Как вы можете видеть в opcode, движок не нуждается в попытке получить константу, потому что теперь rõно, где она находится, и поскольку это статическое значение, оно уже находится в памяти.
Кроме того, оператор IF
исчез, потому что другая сторона оператора IS_IDENTITCAL
– статическая строка (‘Linux
‘), поэтому оператор IF
может быть помечен как “true
” без накладных расходов на интерпретацию его при каждом выполнении.
Вот почему у вас есть большая власть влиять на окончательную производительность вашего PHP-кода.
Заключение
Надеюсь, это была интересная тема. Как я упоминал в начале статьи, я получаю много преимуществ от использования этого тактика, и, фактически, они также используются в наших пакетах.
Вы можете посмотреть пример здесь того, как я использовал эти советы в нашем PHP-пакете для оптимизации его производительности.
Если вы хотите узнать больше о проблемах построения компании, управляемой разработчиками, вы можете следить за мной в LinkedIn.
Source:
https://dzone.com/articles/php-opcode-improve-application-performance