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

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.


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.