简体   繁体   中英

Is PHP usort really so slow or am I doing something wrong?

I have an array (Well, a PHP array... which is not really an array. But you get the point.) of objects representing SMSs. One of the fields in these objects is of type DateTime, and I want to sort the array by that field. I can not sort the data in DB, I'm receiving it from a web service that I can not change , so please don't suggest that. I sort the array with the following snippet of code:

usort($smsMessages, function ($a, $b) { 
    if ($a->SendTime == $b->SendTime) {
        return 0;
    }

    return ($a->SendTime < $b->SendTime) ? -1 : 1;
});

This works, but it takes 160 seconds to sort 30.000 elements.

Now, I know that php is slow, but this is ridiculous. Is there something wrong with the way I wrote this? Is usort known to be slow/broken/buggy? Should I use another method? Roll my own?

You could try speeding up the above code to see if the sorting is in fact the bottle neck, you could try speeding it up by using a global function with it and shortening the code ( Disclaimer: massive microoptimization, could be this is not where your issue is at!) like so:

function sort_function($a, $b){
 $a = $a->SendTime;
 $b = $b->SendTime;
 if ($a == $b) return 0;
 return ($a < $b) ? -1 : 1;
}

usort($smsMessages,'sort_function');

Assuming most SendTimes are not equal this should in fact speed things up.

But please understand that the above is a very slight speedup only. If you actually see things got to like 140s => you can blame usort here. In all likelihood though, the above suggestion's value for you lies in learning that the usort part of things is not your issue in my opinion.

Added after more input below:

After likely having learnt that this is all about a lack of memory (the numbers for usage you posted are about the system overall, I cannot deduce how much of those 256MB are actually in use without more knowledge of these objects :) ), how does this code compare in runtime for you ?

$dates = array();
foreach ($smsMessages as $key => $obj) {
    $dates[$key] = $obj->SendTime;
}

asort($dates);
$dates = array_keys($dates);
$sorted = array();
foreach ($dates as $key) {
    $sorted[] = &$smsMessages[$key];
}

This should need significantly less memory since it doesn't use an implicit foreach loop on the huge array but just on the array keys.

Try this:

First, add "true" to the json_decode as a second parameter, so you will get an associative array instead of array of objects. (I would also recommend to try this to speed up JSON: https://github.com/RustJason/php-rapidjson - it requires PHP7 though)

And then:

$sentTime = [];
foreach ($smsMessages as $key => $element) {
    $sentTime[$key] = strtotime($element['sent']);
}
array_multisort($sentTime, SORT_DESC, $smsMessages);

(0.19 secs on my comp.)

You can convert some $smsMessages into objects later at the moment when you really need them with (object)$smsMessage or using your own/customized method.

I had the same issue. We needed to sort 2-10 million arrays. Each array contained about 30 fields (strings, integers and NULLs). The first field was a unique integer that we used for sorting.

We used PHP 7.1

It took 4710 seconds (= 78.5 minutes) to sort 2,028,830 items on AWS EC2 r4.large.

Our code looked like:

usort($this->rows, function ($item1, $item2) {
        return $item1[0] <=> $item2[0];
});

Then I figured out that replacing $this->rows with $rows makes it almost 4 times faster:

usort($rows, function ($item1, $item2) {
        return $item1[0] <=> $item2[0];
});

It decreased execution time from 4710 to 1195 seconds.

Another approach is to use Min Heap for $this->rows instead of plain PHP array [] . It leads to about the same performance improvement. In this case you don't need usort at all.

Bottom line: 1. but yes, it does take surprisingly huge amount of time even after changes above. 2. usort is way quicker than MinHeap for already sorted arrays.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM