Alternativa a get_posts () debido al bloqueo de caché de subprocesos múltiples

8

Estoy usando pthreads para crear múltiples hilos. Cada uno de esos hilos en un punto intenta usar get_posts()lo siguiente:

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

$posts_list = get_posts($args);

Sin embargo, termino con el siguiente bloqueo:

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

TENGA EN CUENTA que cuando hago la misma get_posts()llamada en una sección de código que no está enhebrada, no tengo el bloqueo.

Ahora, mi pregunta, ¿cómo llamar get_posts()desde un hilo pthread ? Y si no puedo hacer eso, ¿cuál es la alternativa?

Gracias.


Actualizar

Aquí hay un código de muestra

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
fuente
eso no es un bloqueo, es un error ..... debe corregir su código para que no haya un error. En cualquier caso, las bibliotecas php no siempre son seguras para la multitarea, por lo que el problema podría estar en algo totalmente diferente.
Mark Kaplun
Para agregar, si hay un código que debe protegerse para la ejecución "al mismo tiempo" del que necesita usar mutexes, pero eso está fuera del alcance aquí.
Mark Kaplun
@ MarkKaplun - Gracias por su aporte. Sin embargo, parece que se perdió el punto en el que afirmo que " cuando hago la misma get_posts()llamada en una sección de código que no está enhebrada, no tengo el bloqueo "; entonces no es un problema con mi get_posts($args)llamada. Además, no hay código que deba protegerse en este momento, solo estoy leyendo desde la base de datos de WordPress get_posts($args).
Greeso
3
@ MarkKaplun - ¿Qué te pasa? ¿Por qué eres tan negativo y tan agresivo? ¿Por qué supone que no entiendo la multitarea y sugiere que no debería usar pthreads? Incluso si tiene razón, ¿no se supone que debemos intentar lo que no entendemos para expandir nuestros conocimientos y límites? ¿Y no es este sitio acerca de hacer preguntas si no sabe cómo hacer una determinada cosa? No estoy fingiendo nada. Encontré un error, me di cuenta de que se debe al uso de pthreads y estoy pidiendo una solución, ya sea una configuración o una solución de programación. Esperaba una respuesta constructiva tuya.
Greeso
2
Hasta que realmente sepamos que WordPress no es la razón para romper este código, es un tema.
fuxia

Respuestas:

2

Dado que hay tantos votos a favor de la pregunta, aunque los problemas de subprocesamiento múltiple son demasiado amplios para un formato de respuesta, intentaré explicar por qué no debe usar la API de WordPress de forma multiproceso ...

TL; DR: no se supone que PHP esté preparado para subprocesos múltiples, el problema no es PHP en sí, sino principalmente las bibliotecas que utiliza. Es por eso que se recomienda no utilizar el modo de ejecución multiproceso en apache, aunque en teoría debería ser algo más rápido. Para agregar al problema de que la capa subyacente no está lista para múltiples subprocesos, el núcleo de WordPress viola el requisito más básico de múltiples subprocesos: no hay acceso libre a globales.

¿Cuál es el problema con los globales en un entorno multiproceso? supongamos que tenemos el código de aspecto ingenuo

function inc() {
  global $g;

  $g++;
}

Si bien es solo un trazador de líneas, no es una operación atómica para la CPU, y se requieren varias instrucciones de nivel de máquina para ejecutarlo realmente. Algo como

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

Ahora supongamos que tenemos dos hilos AB que llaman inc()al "mismo tiempo" (obviamente con una sola CPU no existe el mismo tiempo), y que el valor inicial de $ g es 0, ¿cuál sería el valor de $ g después de que ambos hilos terminaron? Dependerá de cómo maneje el sistema operativo los subprocesos múltiples, cuándo cambia entre hilos. En los sistemas operativos de estilo "anterior", era el trabajo del subproceso declarar llamando a una API que se le puede quitar el control, pero eso genera muchos problemas con procesos de comportamiento incorrecto que bloquean el sistema en el sistema operativo "moderno" que toma el sistema operativo control cuando quiera. En la vida real, el resultado del código será que $ g tendrá un valor de 2, pero también existe la siguiente posibilidad

En el contexto 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

El resultado final es que $ g tiene el valor de 1.

Obviamente, los globales no son el único problema y el manejo de entradas y salidas también es un núcleo para problemas de multiples hilos.

En un código de subprocesamiento adecuado, use lock / mutex / semaphore / pipe / socket ... para serializar el acceso a dichos recursos globales para asegurarse de que la operación tendrá un resultado predecible. Wordpress no hagas eso.

Demonios, WordPress ni siquiera es seguro para múltiples procesos. La mayoría de las veces se sale con la suya porque el esquema de DB está construido de una manera que, en el uso de la vida real, evita la necesidad de modificar los mismos datos de diferentes procesos (diferentes publicaciones tienen diferentes filas y no comparten datos), pero observe el código de la barra lateral / widgets e intente imaginar qué sucederá si dos administradores intentan agregar un widget diferente exactamente al mismo tiempo. Como esto requerirá la manipulación de una opción específica, el resultado final puede ser ambos widgets agregados o solo uno de ellos.

De vuelta a multitrading. En Unix, a diferencia de Windows, el costo adicional de generar un proceso en lugar de un subproceso es insignificante, por lo tanto, usar wp_remote_getuna url especial para invocar un "subproceso" adicional es algo muy legítimo y evitar casi todos los obstáculos asociados con el subprocesamiento múltiple.

Mark Kaplun
fuente
Esto está bien explicado. Gracias. También descubrí que se está eliminando la compatibilidad con pthreads para trabajar con apache . Para que los pthreads funcionen, debe estar dentro de un entorno CLI . Para mí, necesito pthreads , pero pospondré esta solución hasta después del lanzamiento (es decir, una mejora). Además, tendré que configurar WordPress como un entorno CLI (detalles aquí wp-cli.org ); hacerlo me permitirá trabajar en un entorno pthreads / WordPress desde CLI, permitiéndome hacer el trabajo pesado en el backend sin apache. Gracias de nuevo.
Greeso
Solo para agregar, restringiré pthreads para tratar problemas no relacionados con db. Y según su sugerencia, use mutex para las escrituras de db.
Greeso
@Greeso, Linux fue diseñado para usar múltiples procesos para manejar las necesidades de ejecución concurrente, generar un nuevo proceso es realmente más seguro y más rápido que usar pthreads ..
Mark Kaplun