问题描述

我使用 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:devwordpresswp-includescache.php on line 123

请注意,当我在没有线程的代码段中进行相同的 get_posts()调用时,我没有崩溃。

现在,我的问题,如何从一个 pthread 线程中调用 get_posts()?如果我不能这样做,还有什么可选择的?

谢谢。


Update

这是示例代码

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

最佳解决方案

既然有这么多的提升这个问题,虽然多线程的问题对于一个答案的格式来说太广泛了,但我将尝试解释为什么你不应该以多线程方式使用 wordpress API ….

长话短说 – PHP 不被假定为多线程准备就绪,问题不是 PHP 本身,而是主要是它使用的库。这就是为什么建议在 apache 中不要使用多线程执行模式,但在理论上应该会更快一些。为了增加底层不是多线程准备就绪的问题,wordpress 核心违反了多线程最基本的要求 – 不能免费访问全局变量。

多线程环境中全局变量的问题是什么?让我们假设我们有天真的寻找代码

function inc() {
  global $g;

  $g++;
}

虽然它只是一个内衬,但它不是 CPU 的原子操作,它需要几个机器级指令来动态执行它。就像是

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

现在假设我们有两个线程 AB,在”same time” 调用 inc()(显然只有一个 CPU 没有同一时间没有这样的事情),并且 $ g 的初始值为 0,那么 $ g 的值将是两个线程完成了?它将取决于操作系统如何处理多线程,何时在线程之间切换。在”older” 样式操作系统中,线程的工作是通过调用 API 来声明控制,但是导致在”modern” OS 中锁定系统的不良行为流程的许多问题,OS 随时可以控制感觉好像在现实生活中,代码的结果将是 $ g 的值为 2,但是还有以下可能性

在 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

最终结果是 $ g 的值为 1 。

显然,全局变量不是唯一的问题,处理输入和输出也是解密问题的核心。

在正确的多线程代码中,您可以使用 lock /mutex /semaphore /pipe /socket …. 来序列化对这些全局资源的访问,以确保对该操作有可预测的结果。 WordPress 不这样做

地狱,wordpress 甚至不是多进程安全。大多数时候它被忽略,因为 DB 模式是以一种在现实生活中使用的方式构建的,从而阻止了从不同进程修改相同数据的需要 (不同的帖子有不同的行,不共享数据),但是看看侧边栏/小工具代码,并尝试想象如果两个管理员尝试在完全相同的时间添加一个不同的小工具会发生什么。因为这将需要操纵一个特定的选项,所以最终的结果可以是添加的小工具,也可以只是其中的一个。

回到多线程。在 unix 中,与 windows 不同,产生一个进程而不是线程的额外成本是可忽略的,因此使用 wp_remote_get 与一些特殊的 url 来调用额外的”thread” 是一个非常合法的事情,并避免几乎所有与多线程相关的陷阱。

参考文献

注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。