Alternativa a get_posts () a causa dell'arresto anomalo della cache multithreading


8

Sto usando pthreads per creare più thread. Ognuno di questi thread ad un certo punto tenta di utilizzare get_posts()come segue:

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

$posts_list = get_posts($args);

Comunque finisco con il seguente crash:

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

NOTA: quando eseguo la stessa get_posts()chiamata in una sezione di codice non thread, non ho il crash.

Ora, la mia domanda, come chiamare get_posts()dall'interno di un thread pthread ? E se non posso farlo, qual è l'alternativa?

Grazie.


Aggiornare

Ecco un codice di esempio

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();
}

quello non è un arresto anomalo, è un errore ..... dovresti correggere il tuo codice in modo che non ci sia un errore. In ogni caso le librerie php non sono sempre sicure per il multitasking, quindi il problema potrebbe essere con qualcosa di totalmente diverso.
Mark Kaplun il

Per aggiungere, se esiste un codice che deve essere protetto per l'esecuzione "nello stesso momento" di quanto sia necessario utilizzare i mutex, ma qui è fuori portata.
Mark Kaplun il

@MarkKaplun - Grazie per il tuo contributo. Tuttavia, sembra che tu abbia perso il punto in cui dichiaro che " quando faccio la stessa get_posts()chiamata in una sezione di codice che non è sottoposta a thread, non ho il crash "; quindi non è un problema con la mia get_posts($args)chiamata. Inoltre, non esiste un codice che deve essere protetto a questo punto, sto solo leggendo dal DB di WordPress tramite get_posts($args).
Greeso,

3
@MarkKaplun - Cosa c'è che non va in te? Perché sei così negativo e così aggressivo? Perché pensi che non capisca il multitasking e suggerisci che non dovrei usare pthreads? Anche se hai ragione, non dovremmo provare ciò che non capiamo per espandere le nostre conoscenze e i nostri limiti? E questo sito non fa domande se non sai come fare una determinata cosa? Non sto fingendo nulla. Ho riscontrato un errore, mi sono reso conto che è dovuto all'utilizzo di pthreads e sto chiedendo una soluzione, una configurazione o una soluzione alternativa alla programmazione. Speravo in una risposta costruttiva da parte tua.
Greeso,

2
Fino a quando non sapremo davvero che WordPress non è la ragione per violare questo codice, è sull'argomento.
fuxia

Risposte:


2

Dato che ci sono così tanti voti positivi sulla domanda, anche se i problemi del multithreading sono troppo ampi per un formato di risposta, cercherò di spiegare perché non dovresti usare l'API di wordpress in modo multithread ....

TL; DR - PHP non si presume che sia pronto per il multithreading, il problema non è PHP stesso ma principalmente le librerie che utilizza. Questo è il motivo per cui si consiglia di non utilizzare la modalità di esecuzione multithread in apache sebbene in teoria dovrebbe essere un po 'più veloce. Per aggiungere al problema che il layer sottostante non è pronto per il multithread, il core di wordpress viola i requisiti più elementari del multithread: nessun accesso gratuito ai globali.

Qual è il problema con i globali nell'ambiente multithread? supponiamo di avere il codice dall'aspetto ingenuo

function inc() {
  global $g;

  $g++;
}

Sebbene sia solo un liner, non è un'operazione atomica per la CPU e ci vogliono diverse istruzioni a livello di macchina per eseguirla actoally. Qualcosa di simile a

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

Ora supponiamo che abbiamo due thread AB che chiamano inc()"contemporaneamente" (ovviamente con una sola CPU non esiste una cosa uguale alla stessa) e che il valore iniziale di $ g è 0, quale sarebbe il valore di $ g dopo che entrambi i thread sono terminati? Dipenderà da come il sistema operativo gestisce il multithreading, quando passa da un thread all'altro. Nei sistemi operativi "più vecchi" era compito del thread dichiarare chiamando un'API che il controllo può essere preso da esso, ma ciò porta a molti problemi con processi scorretti che bloccano il sistema per ciò nel sistema operativo "moderno" che il sistema operativo accetta controllo quando mai ne hai voglia. Nella vita reale il risultato del codice sarà che $ g avrà un valore di 2, ma esiste anche la seguente possibilità

Nel contesto di 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

Il risultato finale è che $ g ha il valore di 1.

Ovviamente i globi non sono l'unico problema e la gestione di input e output è anche un elemento centrale per i problemi di mutithreading.

Nel corretto codice multithreading si utilizza lock / mutex / semaphore / pipe / socket .... per serializzare l'accesso a tali risorse globali per assicurarsi che ci sia un risultato prevedibile per l'operazione. Wordpress non lo fa.

Inferno, wordpress non è nemmeno sicuro per più processi. Il più delle volte se la cava perché lo schema DB è costruito in un modo che nella vita reale impedisce la necessità di modificare gli stessi dati da processi diversi (post diversi hanno righe diverse e non condividono dati), ma guarda il codice della barra laterale / dei widget e prova a immaginare cosa accadrà se due amministratori provassero ad aggiungere un widget diverso esattamente nello stesso momento. Poiché ciò richiederà la manipolazione di un'opzione specifica, il risultato finale può essere aggiunto a entrambi i widget o solo uno di essi.

Torna al multithrading. In unix, a differenza di Windows, il costo aggiuntivo di spawn di un processo invece di thread è trascurabile, pertanto l'utilizzo wp_remote_getdi un URL speciale per invocare "thread" aggiuntivo è una cosa molto legittima da fare ed evitare quasi tutte le insidie ​​associate al multithreading.


Questo è ben spiegato. Grazie. Ho anche scoperto che il supporto per far funzionare pthreads con Apache . Per far funzionare i pthread , dovrebbe essere all'interno di un ambiente CLI . Per me, ho bisogno di pthreads , ma rimanderò questa soluzione a dopo il rilascio (ovvero, un miglioramento). Inoltre, dovrò impostare WordPress come un ambiente CLI (dettagli qui wp-cli.org ); farlo mi consentirà di lavorare in un ambiente pthreads / WordPress dalla CLI, permettendomi di fare il lavoro pesante sul backend senza apache. Grazie ancora.
Greeso,

Solo per aggiungere, limiterò pthreads per affrontare problemi non correlati al db. E secondo il tuo suggerimento, usa mutex per le scritture in db.
Greeso,

@Greeso, Linux è stato progettato per utilizzare più processi per gestire le esigenze di esecuzione simultanea, generare un nuovo processo è davvero più sicuro e veloce come usare pthreads ..
Mark Kaplun,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.