Maison > développement back-end > PHP7 > Préchargement en PHP 7.4 (préchargement Opcache)

Préchargement en PHP 7.4 (préchargement Opcache)

藏色散人
Libérer: 2023-02-17 13:16:02
original
7349 Les gens l'ont consulté

Dans PHP 7.4, la prise en charge du préchargement a été ajoutée, une fonctionnalité qui peut améliorer considérablement les performances de votre code.

En un mot, voici comment cela fonctionne :

● Afin de précharger le fichier, vous devez écrire un script PHP personnalisé

● Ce script démarre sur le serveur Exécuté une fois

● Tous les fichiers préchargés sont disponibles en mémoire pour toutes les requêtes

● Les modifications apportées aux fichiers préchargés n'auront aucun impact jusqu'au redémarrage du serveur

Regardons de plus près regarde-le.

#Opcache

Bien que le préchargement soit construit sur opcache, ce n'est pas exactement la même chose. Opcache prendra vos fichiers sources PHP, les compilera en "opcodes", puis stockera ces fichiers compilés sur le disque.

Vous pouvez considérer les opcodes comme des représentations de code de bas niveau qui sont facilement interprétées au moment de l'exécution. Par conséquent, opcache ignore l'étape de conversion entre le fichier source et ce dont l'interpréteur PHP a réellement besoin au moment de l'exécution. Une immense victoire !

Mais nous avons plus à gagner. Les fichiers mis en cache ne connaissent pas les autres fichiers. Si la classe A s'étend de la classe B, elles doivent toujours être liées entre elles au moment de l'exécution. De plus, opcache effectue une vérification pour voir si le fichier source a été modifié et invalidera son cache sur cette base.

C'est donc ici que le préchargement entre en jeu : il compile non seulement les fichiers sources en opcodes, mais relie également les classes, les traits et les interfaces associés. Il enregistre ensuite ce blob « compilé » de code exécutable (c'est-à-dire : le code que l'interpréteur PHP peut utiliser) en mémoire.

Désormais, lorsqu'une requête atteint le serveur, celle-ci peut utiliser des parties de la base de code déjà chargées en mémoire sans entraîner de surcharge.

Alors, qu'entend-on par « partie de la base de code » ?

# Le préchargement en pratique

Afin de précharger, le développeur doit indiquez au serveur quels fichiers charger. Cela a été fait avec un simple script PHP et il n’y avait vraiment rien de difficile.

Les règles sont simples :

● Vous fournissez un script de préchargement et liez-le à votre fichier php.ini à l'aide de la commande opcache.preload.

● Chaque fichier PHP que vous souhaitez précharger doit être transmis à opcache_compile_file(), ou une seule fois dans le script de préchargement.

Supposons que vous souhaitiez précharger un framework, tel que Laravel. Votre script doit parcourir tous les fichiers PHP du répertoire supplier/laravel et les ajouter les uns après les autres.

Lien vers ce script dans php.ini comme suit :

opcache.preload=/path/to/project/preload.php
Copier après la connexion

Il s'agit d'une implémentation factice :

$files = /* An array of files you want to preload */;
foreach ($files as $file) {
    opcache_compile_file($file);
}
Copier après la connexion

# AVERTISSEMENT : impossible de précharger les classes liées inutilisées

etc., il y a un avertissement ! Afin de précharger les fichiers, leurs dépendances (interfaces, traits et classes parent) doivent également être préchargées.

S'il y a des problèmes avec les dépendances de classe, vous serez averti au démarrage du serveur :

Can't preload unlinked class 
Illuminate\Database\Query\JoinClause: 
Unknown parent 
Illuminate\Database\Query\Builder
Copier après la connexion

Écoutez, opcache_compile_file() analysera un fichier mais ne l'exécutera pas. Cela signifie que si une classe a des dépendances qui ne sont pas préchargées, elle ne peut pas être préchargée elle-même.

Ce n'est pas un problème fatal et votre serveur fonctionnera correctement. Mais vous n’obtiendrez pas tous les fichiers préchargés souhaités.

Heureusement, il existe un moyen de garantir que le fichier lié est également chargé : vous pouvez utiliser require_once au lieu de opcache_compile_file et laisser le chargeur automatique enregistré (probablement celui du compositeur) s'occuper du reste.

$files = /* All files in eg. vendor/laravel */;
foreach ($files as $file) {
    require_once($file);
}
Copier après la connexion

Il y a quelques autres choses à noter. Par exemple, si vous essayez de précharger Laravel, certaines classes du framework dépendent d'autres classes qui n'existent pas encore. Par exemple, le cache du système de fichiers d'éclairage de la classe de cache du système de fichiers dépend de LeagueFlysystemCachedStorageAbstractCache, et si vous n'avez jamais utilisé le cache du système de fichiers, vous ne pourrez peut-être pas l'installer dans votre projet.

Vous pouvez rencontrer des erreurs « classe non trouvée » lorsque vous essayez de tout précharger. Heureusement, dans une installation par défaut de Laravel, il n'existe que quelques-unes de ces classes et peuvent être facilement ignorées. Pour plus de commodité, j'ai écrit une petite classe de préchargement pour faciliter l'ignorance des fichiers, comme ceci :

class Preloader
{
    private array $ignores = [];
    private static int $count = 0;
    private array $paths;
    private array $fileMap;
    public function __construct(string ...$paths)
    {
        $this->paths = $paths;
        // We'll use composer's classmap
        // to easily find which classes to autoload,
        // based on their filename
        $classMap = require __DIR__ . '/vendor/composer/autoload_classmap.php';
        $this->fileMap = array_flip($classMap);
    }
    
    public function paths(string ...$paths): Preloader
    {
        $this->paths = array_merge(
            $this->paths,
            $paths
        );
        return $this;
    }
    public function ignore(string ...$names): Preloader
    {
        $this->ignores = array_merge(
            $this->ignores,
            $names
        );
        return $this;
    }
    public function load(): void
    {
        // We'll loop over all registered paths
        // and load them one by one
        foreach ($this->paths as $path) {
            $this->loadPath(rtrim($path, '/'));
        }
        $count = self::$count;
        echo "[Preloader] Preloaded {$count} classes" . PHP_EOL;
    }
    private function loadPath(string $path): void
    {
        // If the current path is a directory,
        // we'll load all files in it 
        if (is_dir($path)) {
            $this->loadDir($path);
            return;
        }
        // Otherwise we'll just load this one file
        $this->loadFile($path);
    }
    private function loadDir(string $path): void
    {
        $handle = opendir($path);
        // We'll loop over all files and directories
        // in the current path,
        // and load them one by one
        while ($file = readdir($handle)) {
            if (in_array($file, ['.', '..'])) {
                continue;
            }
            $this->loadPath("{$path}/{$file}");
        }
        closedir($handle);
    }
    private function loadFile(string $path): void
    {
        // We resolve the classname from composer's autoload mapping
        $class = $this->fileMap[$path] ?? null;
        // And use it to make sure the class shouldn't be ignored
        if ($this->shouldIgnore($class)) {
            return;
        }
        // Finally we require the path,
        // causing all its dependencies to be loaded as well
        require_once($path);
        self::$count++;
        echo "[Preloader] Preloaded `{$class}`" . PHP_EOL;
    }
    private function shouldIgnore(?string $name): bool
    {
        if ($name === null) {
            return true;
        }
        foreach ($this->ignores as $ignore) {
            if (strpos($name, $ignore) === 0) {
                return true;
            }
        }
        return false;
    }
}
Copier après la connexion

En ajoutant cette classe dans le même script de préchargement, nous pouvons maintenant charger ainsi l'intégralité du framework Laravel :

// …
(new Preloader())
    ->paths(__DIR__ . '/vendor/laravel')
    ->ignore(
        \Illuminate\Filesystem\Cache::class,
        \Illuminate\Log\LogManager::class,
        \Illuminate\Http\Testing\File::class,
        \Illuminate\Http\UploadedFile::class,
        \Illuminate\Support\Carbon::class,
    )
    ->load();
Copier après la connexion

#travail ?

C'est bien sûr la question la plus importante : tous les fichiers sont-ils chargés correctement ? Vous pouvez tester cela simplement en redémarrant le serveur puis en transférant la sortie de opcache_get_status() dans un script PHP. Vous verrez qu'il possède une clé appelée preload_statistics, qui répertoriera toutes les fonctions, classes et scripts préchargés ainsi que la mémoire consommée par les fichiers préchargés.

Prise en charge de # Composer

Une fonctionnalité prometteuse pourrait être la solution de préchargement automatique basée sur Composer, qui est déjà utilisée par la plupart des projets PHP modernes. Les gens travaillent sur l'ajout d'une option de configuration de préchargement dans composer.json qui générera les fichiers de préchargement pour vous ! Actuellement, cette fonctionnalité est encore en développement, mais vous pouvez la suivre ici !

# Exigences du serveur

Il y a deux autres choses importantes à mentionner concernant les devops lors de l'utilisation du préchargement.

Comme vous le savez déjà, vous devez spécifier une entrée dans le php.ini pour le préchargement. Cela signifie que si vous utilisez un hébergement mutualisé, vous ne pourrez pas configurer PHP librement. En pratique, vous avez besoin d'un serveur dédié (virtuel) pour pouvoir optimiser les fichiers préchargés pour des projets individuels. Rappelez-vous ceci.

N'oubliez pas non plus que vous devez redémarrer le serveur à chaque fois que vous devez recharger le fichier mémoire (cela est suffisant si vous utilisez php-fpm). Cela peut paraître évident pour la plupart des gens, mais cela mérite quand même d’être mentionné.

#Performance

Passons maintenant à la question la plus importante : le préchargement améliore-t-il vraiment les performances

La réponse est oui : Partagée par Ben Morel Voici les résultats ? quelques repères, qui peuvent être trouvés dans la même question du compositeur liée précédemment.

Fait intéressant, vous pouvez décider de précharger uniquement les "classes chaudes", qui sont des classes fréquemment utilisées dans votre base de code. Les tests de Ben montrent que le chargement d'environ 100 classes populaires génère en réalité de meilleurs gains de performances que le préchargement de toutes les classes. C'est la différence entre une augmentation des performances de 13 % et 17 %.

Bien sûr, les classes à précharger dépendent de votre projet spécifique. Il est sage de précharger autant que possible au début. Si vous avez besoin d'une petite augmentation en pourcentage, vous devrez surveiller votre code au moment de l'exécution.

Bien entendu, tout ce travail peut être automatisé et pourrait être possible à l'avenir.

Maintenant, la chose la plus importante à retenir est que composer ajoutera un support pour que vous n'ayez pas à créer les fichiers de préchargement vous-même, et il sera facile de configurer cette fonctionnalité sur votre serveur tant que vous en avez le contrôle total.

Traduction : https://stitcher.io/blog/preloading-in-php-74

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal