Alternativa para get_posts () devido a falha no cache multithreading

8

Estou usando pthreads para criar vários threads. Cada um desses threads em um ponto tenta usar da get_posts()seguinte maneira:

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

$posts_list = get_posts($args);

No entanto, acabo com a seguinte falha:

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

Observe que, quando faço a mesma get_posts()chamada em uma seção de código que não é encadeada, não tenho a falha.

Agora, minha pergunta, como chamar get_posts()de dentro de um thread pthread ? E se eu não posso fazer isso, qual é a alternativa?

Obrigado.


Atualizar

Aqui está o código de exemplo

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
fonte
que não é uma falha, é um erro ..... você deve corrigir seu código para que não ocorra um erro. De qualquer forma, as bibliotecas php nem sempre são seguras para multitarefa, portanto o problema pode estar em algo totalmente diferente.
precisa
Para adicionar, se houver um código que precise ser protegido para execução "no mesmo horário", você precisará usar mutexes, mas isso está fora do escopo aqui.
precisa
@ MarkKaplun - Obrigado pela sua contribuição. No entanto, parece que você perdeu o ponto em que afirmo que " quando faço a mesma get_posts()chamada em uma seção de código que não é encadeada, não tenho a falha "; portanto, não há problema com minha get_posts($args)ligação. Além disso, não há código que precise ser protegido neste momento, estou apenas lendo no banco de dados do WordPress via get_posts($args).
Greeso 24/12
3
@ MarkKaplun - O que há de errado com você? Por que você é tão negativo e tão agressivo? Por que você acha que eu não entendo multitarefa e sugere que não devo usar pthreads? Mesmo se você estiver correto, não devemos tentar o que não entendemos para expandir nosso conhecimento e limites? E este site não é sobre fazer perguntas se você não sabe como fazer uma determinada coisa? Não estou fingindo nada. Eu encontrei um erro, percebi que era devido ao uso de pthreads e estou pedindo uma solução, seja uma solução alternativa ou uma solução de programação. Eu estava esperando uma resposta construtiva de si mesmo.
Greeso
2
Até que realmente saibamos que o WordPress não é a razão para quebrar esse código, ele está no tópico.
fuxia

Respostas:

2

Como existem muitos votos positivos para a pergunta, embora os problemas de multithreading sejam muito amplos para o formato de uma resposta, tentarei explicar por que você não deve usar a API do wordpress de maneira multithread.

Não se supõe que TL; DR - PHP esteja pronto para multithreading, o problema não é o próprio PHP, mas principalmente as bibliotecas que ele usa. É por isso que é recomendável não usar o modo de execução multithread no apache, embora em teoria deva ser um pouco mais rápido. Para aumentar o problema de a camada subjacente não estar pronta para multithread, o wordpress core viola o requisito mais básico de multithread - sem acesso livre aos globais.

Qual é o problema com globals em um ambiente multithread? vamos assumir que temos o código de aparência ingênua

function inc() {
  global $g;

  $g++;
}

Embora seja apenas um liner, não é uma operação atômica para a CPU, e são necessárias várias instruções no nível da máquina para executá-la actoalmente. Algo como

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

Agora vamos supor que temos dois threads AB que chamam inc()ao mesmo tempo (obviamente, com apenas uma CPU não existe o mesmo tempo) e que o valor inicial de $ g é 0, qual seria o valor de $ g depois que os dois threads terminaram? Depende de como o sistema operacional lida com multithreading, quando ele alterna entre threads. Nos sistemas operacionais de estilo "mais antigo", era o trabalho do encadeamento declarar, chamando uma API que o controle pode ser retirado, mas isso leva a muitos problemas com processos de mau comportamento que bloqueiam o sistema no sistema "moderno" que o sistema operacional utiliza. controlar sempre que lhe apetecer. Na vida real, o resultado do código será que $ g terá o valor 2, mas também existe a seguinte possibilidade

No 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

O resultado final é que $ g tem o valor de 1.

Obviamente, os globais não são o único problema e o manuseio de entradas e saídas também é essencial para problemas de leitura mútua.

No código multithreading adequado, você usa lock / mutex / semáforo / pipe / soquete .... para serializar o acesso a esses recursos globais para garantir que haverá um resultado previsível para a operação. Wordpress não faz isso.

Inferno, o wordpress não é seguro para vários processos. Na maioria das vezes, ele se livra disso porque o esquema do banco de dados é construído de uma maneira que, na vida real, impede a necessidade de modificar os mesmos dados de diferentes processos (postagens diferentes têm linhas diferentes e não compartilham dados), mas observe o código da barra lateral / widgets e tente imaginar o que acontecerá se dois administradores tentarem adicionar um widget diferente exatamente ao mesmo tempo. Como isso exigirá a manipulação de uma opção específica, o resultado final pode ser um dos dois widgets adicionados ou apenas um deles.

Voltar para multithrading. No unix, diferentemente do Windows, o custo adicional de gerar um processo em vez de encadear é insignificante, portanto, usar wp_remote_getcom algum URL especial para chamar "encadeamento" adicional é uma coisa muito legítima a ser feita e evitar quase todas as armadilhas associadas ao multithreading.

Mark Kaplun
fonte
Isso está bem explicado. Obrigado. Também acabei de descobrir que o suporte ao pthreads para trabalhar com o apache está sendo removido. Para fazer o pthreads funcionar, ele deve estar dentro de um ambiente da CLI . Para mim, preciso de pthreads , mas adiarei esta solução até depois do lançamento (ou seja, um aprimoramento). Além disso, precisarei configurar o WordPress como um ambiente CLI (detalhes aqui wp-cli.org ); isso permitirá que eu trabalhe em um ambiente pthreads / WordPress da CLI, permitindo que eu faça o trabalho pesado no backend sem apache. Thaks novamente.
Greeso 28/12/15
Apenas para adicionar, restringirei os pthreads para lidar com problemas não relacionados ao banco de dados. E conforme sua sugestão, use o mutex para gravações de banco de dados.
Greeso 28/12
@Greeso, linux foi projetado para o uso de vários processos para lidar com as necessidades de execução simultâneos, gerando um novo processo é realmente mais seguro e mais rápido que usando pthreads ..
Mark Kaplun