Alternative to get_posts() due to multithreading cache crash

Since there are so many upvotes to the question, although the issues of multithreading are just too broad for a format of an answer, I will try to explain why you should not use wordpress API in a multithreaded way….

TL;DR – PHP is not assumed to be multithreading ready, the problem is not PHP itself but mainly the libraries it uses. This is why it is recommended not to use the multithreaded execution mode in apache although in theory it should be somewhat faster. To add to the problem of underlying layer not being multithread ready, wordpress core violates the most basic requirement of multithread- no free access to globals.

What is the problem with globals in multithreaded enviroment? lets assume we have the naive looking code

function inc() {
  global $g;

  $g++;
}

While it is just a one liner, it is not an atomic operation for the CPU, and it take several machine level instruction to actoally execute it. Some thing like

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

Now lets assume we have two threads A B that call inc() at the “same time” (obviously with only one CPU there is no such thing as same time), and that the initial value of $g is 0, what would be the value of $g after both threads finished? It will depend on how the OS handles multithreading, when does it switch between threads. In “older” style OSes it was the job of the thread to declare by calling an API that control can be taken from it, but that leads to many problems with bad behaving processes locking down the system therefor in “modern” OS the OS takes control when ever it feels like it. In real life the result of the code will be that $g will have a value of 2, but there is also the following possibility

In the context of 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

End result is that $g has the value of 1.

Obviously globals are not the only problem and handling inputs and outputs is also a core for mutithreading problems.

In proper multithreading code you use lock/mutex/semaphore/pipe/socket…. to serialize access to such global resources to make sure there will be a predictable result to the operation.
Wordpress do not do that.

Hell, wordpress is not even multi process safe. Most of the time it gets away with it because the DB schema is built in a way which in real life usage prevents the need to modify the same data from different processes (different posts has different rows and do not share data), but look at the sidebar/widgets code and try to imagine what will happen if two admins would try to add a different widget at exactly the same time. Since this will require the manipulation of one specific option the end result can be either both widgets added or only one of them.

Back to multithrading. In unix, unlike windows, the additional cost of spawning a process instead of thread is negligible, therefor using wp_remote_get with some special url to invoke additional “thread” is a very legitimate thing to do and avoid almost all the pitfalls associated with multithreading.

Leave a Comment