由于多线程缓存崩溃,因此可以替代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();
}

那不是崩溃,而是一个错误.....您应该修复您的代码,以便不会出现错误。无论如何,php库并不总是安全的多任务处理,因此问题可能出在完全不同的东西上。
马克·卡普伦

要添加的是,如果需要在“相同时间”执行时保护代码,而不是使用互斥锁,但是这超出了这里的范围。
马克·卡普伦

@MarkKaplun-感谢您的输入。但是,您似乎错失了以下观点:“ 当我get_posts()在没有线程的代码段中进行相同的调用时,我不会崩溃 ”;所以我的get_posts($args)电话没问题。此外,目前还没有需要保护的代码,我只是通过从WordPress DB中读取get_posts($args)
Greeso

3
@MarkKaplun-你怎么了?你为什么这么消极又那么激进?为什么您认为我不了解多任务处理并建议我不使用pthreads?即使您是正确的,我们不应该尝试尝试我们不了解的内容来扩展我们的知识和限制吗?如果您不知道如何做某件事,这个网站不是在问问题吗?我什么都不装 我遇到了一个错误,我意识到这是由于使用了pthreads而引起的,我正在寻求解决方案,即安装程序或编程变通办法。我希望自己能提供建设性的答案。
格里索2015年

2
直到我们真正知道 WordPress不是破坏此代码的原因之前,它都是主题。
fuxia

Answers:


2

由于对该问题的支持很多,尽管多线程问题对于回答的格式来说太宽泛了,但我将尝试解释为什么您不应该以多线程方式使用wordpress API。

TL; DR-不假定PHP已准备好进行多线程处理,问题不在于PHP本身,而主要在于它使用的库。这就是为什么建议不要在apache中使用多线程执行模式的原因,尽管从理论上讲它应该更快一些。为了增加基础层尚未准备好多线程的问题,wordpress核心违反了多线程的最基本要求,即不能自由访问全局变量。

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

function inc() {
  global $g;

  $g++;
}

尽管它只是一个线性代码,但对于CPU而言并不是原子操作,它需要多条机器级指令来实际执行。就像是

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

现在让我们假设有两个线程AB inc()在“相同时间” 调用(显然只有一个CPU没有相同的时间),并且$ g的初始值为0,那么$ g的值是多少g在两个线程完成之后?这将取决于操作系统如何处理多线程以及何时在线程之间切换。在“较旧”样式的操作系统中,线程的工作是通过调用API来声明可以从中获取控制权,但是这导致了许多不良行为,这些问题导致行为被程序锁定,从而导致操作系统无法使用“现代”操作系统。随时控制感觉。在现实生活中,代码的结果将是$ 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甚至不是多进程安全的。在大多数情况下,它是无法实现的,因为数据库架构的构建方式可以在现实生活中使用,从而无需修改来自不同进程的相同数据(不同的帖子具有不同的行并且不共享数据),但是请看一下边栏/小部件代码,并尝试想象如果两个管理员尝试在同一时间添加不同的小部件会发生什么。由于这将需要操纵一个特定选项,因此最终结果可以是添加两个小部件,也可以仅添加其中一个。

回到多重交易。在unix中,与Windows不同,生成进程而不是线程的额外成本可以忽略不计,因此,使用wp_remote_get一些特殊的url来调用附加的“线程”是一件很合理的事情,并且避免了与多线程相关的几乎所有陷阱。


这是很好的解释。谢谢。我也刚刚发现,删除了对与pache一起使用的pthread的支持。为了使pthreads起作用,它应该在CLI环境中。对我来说,我需要pthreads,但是我会将此解决方案推迟到发行(即增强)之后。另外,我将需要将WordPress设置为CLI命令行工具(在此处详细介绍wp-cli.org);这样做将使我能够在CLI中运行pthreads / WordPress环境,这使我无需使用Apache就可以在后端完成繁重的工作。再次解冻。
Greeso 2015年

补充一下,我将限制pthread处理非数据库相关的问题。并且根据您的建议,将互斥锁用于数据库写入。
2015年

@Greeso,它就被设计成使用多个进程来处理并发执行的需求,产生一个新的进程是非常安全的,并尽可能快地使用并行线程..
马克·卡普伦
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.