Альтернатива get_posts () из-за сбоя многопоточного кэша

8

Я использую pthreads для создания нескольких потоков. Каждый из этих потоков в какой-то момент пытается использовать get_posts()следующее:

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

$posts_list = get_posts($args);

Однако я получаю следующее падение:

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

ПОЖАЛУЙСТА, ОБРАТИТЕ ВНИМАНИЕ, когда я делаю тот же get_posts()вызов в разделе кода, который не является многопоточным, у меня нет сбоя.

Теперь мой вопрос, как позвонить get_posts()из нити pthread ? И если я не могу этого сделать, какова альтернатива?

Спасибо.


Обновить

Вот пример кода

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
источник
это не сбой, это ошибка ..... вы должны исправить свой код, чтобы не было ошибки. В любом случае библиотеки php не всегда безопасны для многозадачности, поэтому проблема может быть в чем-то совершенно ином.
Марк Каплун
Чтобы добавить, если есть код, который должен быть защищен для выполнения «в одно и то же время», чем вам нужно использовать мьютексы, но это здесь выходит за рамки.
Марк Каплун
@MarkKaplun - Спасибо за ваш вклад. Однако кажется, что вы упустили момент, когда я заявляю, что « когда я делаю один и тот же get_posts()вызов в секции кода, которая не является многопоточной, у меня не происходит сбой »; так что это не проблема с моим get_posts($args)звонком. Более того, на данный момент нет кода, который нужно защищать, я просто читаю из БД WordPress через get_posts($args).
Greeso
3
@MarkKaplun - что с тобой? Почему ты такой отрицательный и такой агрессивный? Почему вы считаете, что я не понимаю многозадачность, и предлагаете мне не использовать pthreads? Даже если вы правы, не должны ли мы попробовать то, что не понимаем, чтобы расширить наши знания и ограничения? И разве этот сайт не о том, чтобы задавать вопросы, если вы не знаете, как делаете определенную вещь? Я ничего не притворяюсь. Я обнаружил ошибку, я понял, что это связано с использованием pthreads, и я прошу решение, либо настройка, либо обходной путь программирования. Я надеялся на конструктивный ответ от себя.
Greeso 24.12.15
2
Пока мы действительно не знаем, что WordPress не является причиной взломать этот код, это тема.
Фуксия

Ответы:

2

Поскольку существует множество возражений на этот вопрос, хотя проблемы многопоточности слишком широки для формата ответа, я попытаюсь объяснить, почему не следует использовать WordPress API многопоточным способом ....

TL; DR - PHP не считается готовым к многопоточности, проблема не в самом PHP, а в основном в используемых им библиотеках. Вот почему рекомендуется не использовать многопоточный режим выполнения в Apache, хотя теоретически он должен быть несколько быстрее. Чтобы добавить к проблеме того, что нижележащий слой не готов к многопоточности, ядро ​​WordPress нарушает самое основное требование многопоточности - свободный доступ к глобальным переменным.

В чем проблема глобалов в многопоточной среде? давайте предположим, что у нас есть наивно выглядящий код

function inc() {
  global $g;

  $g++;
}

Хотя это всего лишь одна строка, это не атомарная операция для ЦП, и для ее фактического выполнения требуется несколько инструкций на уровне машины. Что-то вроде

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

Теперь давайте предположим, что у нас есть два потока AB, которые вызывают inc()«в одно и то же время» (очевидно, что только с одним ЦП нет такого понятия, как одно и то же время), и что начальное значение $ g равно 0, что будет значением $ г после окончания обоих потоков? Это будет зависеть от того, как ОС обрабатывает многопоточность, когда она переключается между потоками. В «старых» ОС стиль работы потока заключался в том, чтобы объявить, вызвав API, от которого можно получить контроль, но это приводит ко многим проблемам с процессами с плохим поведением, блокирующими систему для этого в «современных» ОС, которые использует ОС. контроль, когда это кажется В реальной жизни результатом кода будет то, что $ g будет иметь значение 2, но есть также следующая возможность

В контексте А

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

Конечным результатом является то, что $ g имеет значение 1.

Очевидно, глобальные переменные - не единственная проблема, и обработка входных и выходных данных также является ядром для многопоточности.

В правильном многопоточном коде вы используете lock / mutex / semaphore / pipe / socket ...., чтобы сериализовать доступ к таким глобальным ресурсам, чтобы обеспечить предсказуемый результат операции. Wordpress не делает этого.

Черт, WordPress не является даже безопасным для многих процессов. Большую часть времени это обходится без него, потому что схема БД построена таким образом, что в реальной жизни предотвращает необходимость изменять одни и те же данные из разных процессов (разные записи имеют разные строки и не разделяют данные), но посмотрите на код боковой панели / виджетов и попытайтесь представить, что произойдет, если два администратора попытаются добавить другой виджет в одно и то же время. Поскольку это потребует манипулирования одним конкретным параметром, конечным результатом может быть добавление обоих виджетов или только одного из них.

Вернуться к мультитрейдингу. В Unix, в отличие от Windows, дополнительные затраты на создание процесса вместо потока незначительны, поэтому использование wp_remote_getс каким-то специальным URL для вызова дополнительного «потока» является вполне допустимым и позволяет избежать почти всех ловушек, связанных с многопоточностью.

Марк Каплун
источник
Это хорошо объяснено. Спасибо. Я также только что узнал, что поддержка pthreads для работы с apache удалена. Для того чтобы pthreads работал, он должен находиться в среде CLI . Для меня мне нужны pthreads , но я отложу это решение до выпуска (т. Е. Улучшения). Кроме того, мне нужно будет настроить WordPress в качестве среды CLI (подробности здесь wp-cli.org ); Это позволит мне работать со средой pthreads / WordPress из CLI, что позволит мне выполнять тяжелую работу на сервере без Apache. Снова спасибо.
Greeso
Просто добавлю, я ограничу pthreads для решения проблем, не связанных с БД. И согласно вашему предложению, используйте mutex для записи в БД.
Greeso
@ Greeso, linux был разработан для использования нескольких процессов для одновременного выполнения задач, порождая новый процесс, действительно более безопасный и быстрый, чем использование pthreads ..
Марк Каплун,