web-dev-qa-db-fra.com

Alternative à get_posts () en raison d'un plantage de cache multithreading

J'utilise pthreads pour créer plusieurs threads. Chacun de ces threads à un moment donné tente d'utiliser get_posts() comme suit:

$args = array(
    'post_type' => 'post',
    'post_status' => 'any'
);

$posts_list = get_posts($args);

Cependant, je me retrouve avec le crash suivant:

HP Fatal error:  Call to a member function get() on a non-object in C:\dev\wordpress\wp-includes\cache.php on line 123

VEUILLEZ NOTER lorsque je fais le même appel get_posts() dans une section de code qui n'est pas threadée, je n'ai pas le blocage.

Maintenant, ma question, comment appeler get_posts() à partir d'un pthread thread? Et si je ne peux pas faire ça, quelle est l'alternative?

Merci.


Mettre à jour

Voici un exemple de code

class My_Thread extends Thread {

    public function run() {

        /* DO SOME STUFF HERE */

        $args = array(
            'post_type' => 'post',
            'post_status' => 'any'
        );

        $posts_list = get_posts($args); // <------ This is causing the crash
    }
}

// Create a array
$threads = array();

//Iniciate Miltiple Thread
foreach ( range("A", "C") as $i ) {
    $threads[] = new My_Thread($i);
}

// Start The Threads
foreach ($threads as $thread) {
    $thread->start();
}
8
Greeso

Comme il y a tellement de votes positifs à la question, même si les problèmes de multithreading sont trop généraux pour un format de réponse, je vais essayer d'expliquer pourquoi vous ne devriez pas utiliser l'API wordpress de manière multithread ...

TL; DR - PHP n’est pas supposé multithreading, le problème n’est pas PHP, mais principalement les bibliothèques qu’il utilise. C'est pourquoi il est recommandé de ne pas utiliser le mode d'exécution multithread dans Apache, bien qu'en théorie, il devrait être un peu plus rapide. Pour ajouter au problème de la couche sous-jacente n'étant pas compatible multithread, wordpress core viole l'exigence la plus élémentaire de l'accès multithread - aucun accès gratuit aux globals.

Quel est le problème avec les globals dans un environnement multithread? supposons que nous ayons le code naïf

function inc() {
  global $g;

  $g++;
}

Bien qu’il s’agisse d’une couche unique, il ne s’agit pas d’une opération atomique pour le CPU et il faut plusieurs instructions au niveau de la machine pour l’exécuter de manière autonome. Quelque chose comme

move $g to register D
increment register D
move register D to $g

Supposons maintenant que nous avons deux threads AB qui appellent inc() en même temps (de toute évidence avec un seul processeur), et que la valeur initiale de $ g est 0, quelle serait la valeur de $ g après la fin des deux discussions? Cela dépend de la manière dont le système d'exploitation gère le multithreading, quand bascule-t-il entre les threads. Dans les systèmes d’exploitation de type "plus ancien", c’était le rôle du thread de déclarer en appelant une API que le contrôle pouvait en être extrait, mais cela posait de nombreux problèmes en raison de processus inefficaces qui bloquaient le système. contrôlez quand vous en avez envie. Dans la vie réelle, le code aura pour résultat que $ g aura une valeur de 2, mais il existe également la possibilité suivante

Dans le contexte de A

move $g to register D
// value of D is 0
// OS stores the content of registers and switches to thread B
// B increments $g to 1 and finishes working
// OS restores content of registers to the context of thread A
// Value of register D is now 0
increment register D
move register D to $g

Le résultat final est que $ g a la valeur 1.

Les globals ne sont évidemment pas le seul problème et la gestion des entrées et des sorties est également au cœur des problèmes de multithreading.

Dans le code multithreading approprié, vous utilisez lock/mutex/sémaphore/tube/socket ... pour sérialiser l'accès à de telles ressources globales afin de vous assurer que le résultat sera prévisible pour l'opération. Wordpress ne fait pas ça.

Enfer, wordpress n'est même pas multi process safe. La plupart du temps, il s'en sort parce que le schéma de base de données est construit de telle sorte que, dans la vie réelle, il ne soit pas nécessaire de modifier les mêmes données à partir de différents processus (différentes publications ont des lignes différentes et ne partagent pas de données). la barre latérale/widgets code et essayez d'imaginer ce qui se passera si deux administrateurs essayent d'ajouter un widget différent exactement au même moment. Comme cela nécessitera la manipulation d'une option spécifique, le résultat final peut être soit les deux widgets ajoutés, soit un seul d'entre eux.

Retour au multithrading. Sous Unix, contrairement à Windows, le coût supplémentaire de création d’un processus au lieu d’un thread est négligeable. Par conséquent, utiliser wp_remote_get avec une URL spéciale pour appeler un "thread" supplémentaire est une opération très légitime et permet d’éviter presque tous les pièges associés au multithreading.

2
Mark Kaplun