Alternative à get_posts () en raison d'un crash du cache multithreading

8

J'utilise pthreads pour créer plusieurs threads. Chacun de ces threads à un moment donné essaie 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 que lorsque je fais le même get_posts()appel dans une section de code qui n'est pas filetée, je n'ai pas le plantage.

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

Merci.


Mise à 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();
}
Greeso
la source
ce n'est pas un plantage c'est une erreur ..... vous devez corriger votre code pour qu'il n'y ait pas d'erreur. Dans tous les cas, les bibliothèques php ne sont pas toujours sûres pour le multitâche, le problème peut donc être totalement différent.
Mark Kaplun
Pour ajouter, s'il y a du code qui doit être protégé pour une exécution "en même temps", vous devez utiliser des mutex, mais cela sort du cadre ici.
Mark Kaplun
@MarkKaplun - Merci pour votre contribution. Cependant, il semble que vous ayez raté le point où je déclare que " lorsque je fais le même get_posts()appel dans une section de code qui n'est pas enfilée, je n'ai pas le plantage "; donc ce n'est pas un problème avec mon get_posts($args)appel. De plus, il n'y a pas de code qui doit être protégé à ce stade, je lis simplement à partir de la base de données WordPress via get_posts($args).
Greeso
3
@MarkKaplun - Qu'est-ce qui ne va pas chez vous? Pourquoi es-tu si négatif et si agressif? Pourquoi supposez-vous que je ne comprends pas le multitâche et suggérez-vous de ne pas utiliser pthreads? Même si vous avez raison, ne sommes-nous pas censés essayer ce que nous ne comprenons pas pour élargir nos connaissances et nos limites? Et ce site ne consiste-t-il pas à poser des questions si vous ne savez pas comment vous faites une certaine chose? Je ne prétends rien. J'ai rencontré une erreur, je me suis rendu compte qu'elle était due à l'utilisation de pthreads et je demande une solution, soit une configuration, soit une solution de programmation aa. J'espérais une réponse constructive de votre part.
Greeso
2
Jusqu'à ce que nous sachions vraiment que WordPress n'est pas la raison de casser ce code, c'est sur le sujet.
fuxia

Réponses:

2

Puisqu'il y a tellement de votes positifs à la question, bien que les problèmes de multithreading soient tout simplement trop larges pour un format de réponse, j'essaierai d'expliquer pourquoi vous ne devriez pas utiliser l'API wordpress de manière multithread ....

TL; DR - PHP n'est pas supposé être prêt pour le multithreading, le problème n'est pas PHP lui-même 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 qui n'est pas prête pour le multithread, wordpress core viole l'exigence la plus basique du multithread - pas d'accès gratuit aux globaux.

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

function inc() {
  global $g;

  $g++;
}

Bien qu'il ne s'agisse que d'une seule ligne, ce n'est pas une opération atomique pour le CPU, et il faut plusieurs instructions au niveau de la machine pour l'exécuter. 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" (évidemment avec un seul processeur, il n'y a pas de même temps), et que la valeur initiale de $ g est 0, quelle serait la valeur de $ g une fois les deux fils terminés? Cela dépendra de la façon dont le système d'exploitation gère le multithreading, quand basculera-t-il entre les threads. Dans les systèmes d'exploitation de style "plus ancien", le thread devait déclarer en appelant une API que le contrôle pouvait en être retiré, mais cela entraînait de nombreux problèmes avec des processus de mauvais comportement bloquant le système à cet effet dans le système d'exploitation "moderne" que le système d'exploitation prend. contrôler quand il en a envie. Dans la vraie vie, le résultat du code sera que $ g aura une valeur de 2, mais il y a aussi la possibilité suivante

Dans le cadre 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.

De toute évidence, les globaux ne sont pas le seul problème et la gestion des entrées et des sorties est également au cœur des problèmes de mutithreading.

Dans le code multithreading approprié, vous utilisez lock / mutex / semaphore / pipe / socket .... pour sérialiser l'accès à ces ressources globales pour vous assurer qu'il y aura un résultat prévisible à l'opération. Wordpress ne fait pas ça.

Enfer, wordpress n'est même pas sûr pour plusieurs processus. La plupart du temps, il s'en tire car le schéma de base de données est construit d'une manière qui, dans la vie réelle, évite d'avoir à modifier les mêmes données de différents processus (différentes publications ont des lignes différentes et ne partagent pas de données), mais regardez le code de la barre latérale / widgets et essayez d'imaginer ce qui se passera si deux administrateurs tentent d'ajouter un widget différent exactement en même temps. 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 la génération d'un processus au lieu d'un thread est négligeable, donc utiliser wp_remote_getavec une URL spéciale pour invoquer un "thread" supplémentaire est une chose très légitime à faire et évite presque tous les pièges associés au multithreading.

Mark Kaplun
la source
Ceci est bien expliqué. Merci. Je viens également de découvrir que la prise en charge de pthreads pour fonctionner avec apache est supprimée. Pour que pthreads fonctionne, il doit se trouver dans un environnement CLI . Pour moi, j'ai besoin de pthreads , mais je reporterai cette solution après la sortie (c'est-à-dire une amélioration). De plus, je devrai configurer WordPress comme un environnement CLI (détails ici wp-cli.org ); cela me permettra de travailler un environnement pthreads / WordPress à partir de CLI, me permettant de faire le travail lourd au backend sans apache. Merci encore.
Greeso
Juste pour ajouter, je limiterai pthreads pour traiter les problèmes non liés à db. Et selon votre suggestion, utilisez mutex pour les écritures db.
Greeso
@Greeso, Linux a été conçu pour utiliser plusieurs processus pour gérer les besoins d'exécution simultanée, engendrer un nouveau processus est vraiment plus sûr et aussi rapide que l'utilisation de pthreads ..
Mark Kaplun