Phương pháp ưa thích để lưu trữ các mảng PHP (json_encode vs serialization)


608

Tôi cần lưu trữ một mảng dữ liệu liên kết đa chiều trong một tệp phẳng cho các mục đích lưu trữ. Thỉnh thoảng tôi có thể bắt gặp nhu cầu chuyển đổi nó thành JSON để sử dụng trong ứng dụng web của mình nhưng phần lớn thời gian tôi sẽ sử dụng mảng trực tiếp trong PHP.

Sẽ hiệu quả hơn khi lưu trữ mảng dưới dạng JSON hoặc dưới dạng mảng tuần tự PHP trong tệp văn bản này? Tôi đã nhìn xung quanh và dường như trong các phiên bản mới nhất của PHP (5.3), json_decodethực sự nhanh hơn unserialize.

Tôi hiện đang nghiêng về việc lưu trữ mảng dưới dạng JSON vì tôi cảm thấy dễ đọc hơn bởi con người nếu cần thiết, nó có thể được sử dụng trong cả PHP và JavaScript với rất ít nỗ lực và từ những gì tôi đã đọc, thậm chí có thể là nhanh hơn để giải mã (mặc dù không chắc chắn về mã hóa).

Có ai biết về bất kỳ cạm bẫy? Bất cứ ai cũng có điểm chuẩn tốt để hiển thị lợi ích hiệu suất của một trong hai phương pháp?

Câu trả lời:


563

Phụ thuộc vào ưu tiên của bạn.

Nếu hiệu suất là đặc tính lái xe tuyệt đối của bạn, thì bằng mọi cách hãy sử dụng cái nhanh nhất. Chỉ cần chắc chắn rằng bạn có một sự hiểu biết đầy đủ về sự khác biệt trước khi bạn lựa chọn

  • Không giống như serialize()bạn cần thêm tham số bổ sung để giữ cho các ký tự UTF-8 không bị ảnh hưởng: json_encode($array, JSON_UNESCAPED_UNICODE) (nếu không, nó chuyển đổi các ký tự UTF-8 thành các chuỗi thoát Unicode).
  • JSON sẽ không có bộ nhớ về lớp gốc của đối tượng là gì (chúng luôn được khôi phục như các thể hiện của stdClass).
  • Bạn không thể tận dụng __sleep()__wakeup()với JSON
  • Theo mặc định, chỉ các thuộc tính công khai được tuần tự hóa với JSON. (trong PHP>=5.4bạn có thể triển khai JsonSerializable để thay đổi hành vi này).
  • JSON dễ mang theo hơn

Và có lẽ có một vài sự khác biệt khác mà tôi không thể nghĩ ra vào lúc này.

Một bài kiểm tra tốc độ đơn giản để so sánh hai

<?php

ini_set('display_errors', 1);
error_reporting(E_ALL);

// Make a big, honkin test array
// You may need to adjust this depth to avoid memory limit errors
$testArray = fillArray(0, 5);

// Time json encoding
$start = microtime(true);
json_encode($testArray);
$jsonTime = microtime(true) - $start;
echo "JSON encoded in $jsonTime seconds\n";

// Time serialization
$start = microtime(true);
serialize($testArray);
$serializeTime = microtime(true) - $start;
echo "PHP serialized in $serializeTime seconds\n";

// Compare them
if ($jsonTime < $serializeTime) {
    printf("json_encode() was roughly %01.2f%% faster than serialize()\n", ($serializeTime / $jsonTime - 1) * 100);
}
else if ($serializeTime < $jsonTime ) {
    printf("serialize() was roughly %01.2f%% faster than json_encode()\n", ($jsonTime / $serializeTime - 1) * 100);
} else {
    echo "Impossible!\n";
}

function fillArray( $depth, $max ) {
    static $seed;
    if (is_null($seed)) {
        $seed = array('a', 2, 'c', 4, 'e', 6, 'g', 8, 'i', 10);
    }
    if ($depth < $max) {
        $node = array();
        foreach ($seed as $key) {
            $node[$key] = fillArray($depth + 1, $max);
        }
        return $node;
    }
    return 'empty';
}

31
"JSON chuyển đổi các ký tự UTF-8 thành các chuỗi thoát unicode." Không còn nhất thiết phải đúng: bây giờ chúng ta có JSON_UNESCAPED_UNICODE.
TRiG

32
Ở đây chúng tôi gần 5 năm sau và tôi đã thực hiện các bài kiểm tra một lần nữa (chỉ là json_encode) và nó trung bình nhanh hơn khoảng 131% so với việc tuần tự hóa bây giờ. Vì vậy, phải có một số cải tiến khá hay cho chức năng đó trong 5.4.x trên 5.3.x. Cụ thể, tôi đang chạy 5.4.24 trên CentOS 6. Vì vậy, yay cho JSON !!
KyleFarris

8
trong trường hợp của tôi, chúng tôi mã hóa một lần và giải mã rất nhiều, vì vậy chúng tôi làm chuẩn các json_decode vs unserialize và kết quả là JSON dcoded trong ,06662392616272 giây <br> PHP unserialized trong ,093269109725952 giây <br> json_decode () là xấp xỉ 39,99% nhanh hơn so với unserialize ()
AMB

21
Thú vị: nếu bạn chạy mã này trên 3v4l.org , các bản dựng phát triển PHP7 mới nhất chạy tuần tự hóa nhanh hơn json_encode: "serialize () nhanh hơn khoảng 76,53% so với json_encode ()"
marcvangend 9/03/2015

21
2017, PHP 7.1 vàserialize() was roughly 35.04% faster than json_encode()
Elias Soares

239

JSON đơn giản và nhanh hơn định dạng tuần tự hóa của PHP và nên được sử dụng trừ khi :

  • Bạn đang lưu trữ các mảng được lồng sâu json_decode():: "Hàm này sẽ trả về false nếu dữ liệu được mã hóa JSON sâu hơn 127 phần tử."
  • Bạn đang lưu trữ các đối tượng cần được xác nhận là đúng lớp
  • Bạn đang tương tác với các phiên bản PHP cũ không hỗ trợ json_decode

12
Câu trả lời chính xác. Haha, sâu 127 cấp có vẻ hơi điên rồ; rất may tôi chỉ thích 2-3 Bạn có dữ liệu nào để sao lưu thực tế là json_decode / json_encode nhanh hơn unserialize / serialize không?
KyleFarris

1
Tôi đã kiểm tra nó một lúc trước và json xuất hiện nhanh hơn - mặc dù tôi không có dữ liệu nữa.
Greg

47
"5.3.0 Đã thêm độ sâu tùy chọn. Độ sâu đệ quy mặc định được tăng từ 128 lên 512"
giorgio79

4
Tôi sẽ thêm một mục nữa vào danh sách trên: không nên sử dụng json_encode () nếu dữ liệu của bạn có thể chứa các chuỗi UTF-8 không hợp lệ. Nó chỉ đơn giản trả về false cho dữ liệu đó. Hãy thử ví dụ: var_dump (json_encode ("\ xEF \ xEF"));
pako

2
Nó không đúng là nói chung là nhanh hơn. Nếu bạn có một mảng nhỏ với khoảng ~ 500 mục, thì việc hủy kích hoạt / tuần tự hóa thực sự nhanh hơn 200-400% sau đó json_decode / json_encode (PHP 5.6.19)
Adam

59

Tôi đã viết một bài đăng trên blog về chủ đề này: "Lưu trữ một mảng lớn: JSON, tuần tự hóa hoặc var_export? " . Trong bài viết này cho thấy rằng serialization là sự lựa chọn tốt nhất cho các mảng có kích thước nhỏ đến lớn. Đối với mảng rất lớn (> 70MB) JSON là lựa chọn tốt hơn.


8
Các liên kết không có sẵn nữa.
Martin Thoma

1
Cảm ơn, nai sừng, tôi đã cập nhật liên kết. Mặc dù bài viết đã gần 6 năm và có thể không chính xác cho các phiên bản PHP hiện tại.
Taco

Tôi đã thực hiện một số thử nghiệm và thực hiện một chức năng đơn giản để kiểm tra nó, với các mảng lớn (chức năng được sử dụng của Peter Bailey), nhanh hơn json_encode()khoảng 80% đến 150% (thực sự đi lên và xuống) serialize(), với khoảng 300 lần lặp. Nhưng khi sử dụng các mảng nhỏ hơn ( array("teams" => array(1 => array(4 arrays of players), 2 => array(4 arrays of players)))), tôi đã kiểm tra với 750.000 lần lặp và nhanh hơn serialize()khoảng 6% đến 10% trong trường hợp đó. Hàm của tôi mất thời gian trung bình cho tất cả các lần lặp và so sánh chúng. Tôi có thể đăng nó ở đây như một trong những câu trả lời
MiChAeLoKGB

nếu các dữ liệu chỉ được PHP sử dụng, var_export là thứ của tôi. Chỉ cần cẩn thận với các lỗi cú pháp có thể có trong suy nghĩ bao gồm.
Gfra54

3
blog không còn tồn tại
popeye

53

Bạn cũng có thể quan tâm đến https://github.com/phadej/igbinary - nơi cung cấp một 'công cụ' tuần tự hóa khác nhau cho PHP.

Số liệu 'hiệu suất' ngẫu nhiên / tùy ý của tôi, sử dụng PHP 5.3.5 trên chương trình nền tảng 64 bit:

JSON:

  • JSON được mã hóa trong 2.1804969 31076 giây
  • JSON được giải mã trong 9.8368630409241 giây
  • kích thước "chuỗi" nối tiếp: 13993

PHP bản địa:

  • PHP được tuần tự hóa trong 2.9125759601593 giây
  • PHP chưa được xác nhận trong 6.4348418712616 giây
  • kích thước "chuỗi" nối tiếp: 20769

Nhiễm trùng huyết:

  • THẮNG igbinary được tuần tự hóa trong 1.6099879741669 giây
  • THẮNG igbinrary chưa được xác nhận trong 4.7737920284271 giây
  • THẮNG "Chuỗi" nối tiếp Kích thước: 4467

Vì vậy, nó nhanh hơn với igbinary_serialize () và igbinary_unserialize () và sử dụng ít dung lượng đĩa hơn.

Tôi đã sử dụng mã fillArray (0, 3) như trên, nhưng làm cho các khóa mảng dài hơn chuỗi.

igbinary có thể lưu trữ các loại dữ liệu giống như tuần tự hóa riêng của PHP (Vì vậy, không có vấn đề gì với các đối tượng, v.v.) và bạn có thể yêu cầu PHP5.3 sử dụng nó để xử lý phiên nếu bạn muốn.

Xem thêm http://ilia.ws/files/zendcon_2010_hidden_features.pdf - cụ thể là các slide 14/15/16


25

Y vừa kiểm tra serialized và json mã hóa và giải mã, cộng với kích thước nó sẽ lấy chuỗi được lưu trữ.

JSON encoded in 0.067085981369 seconds. Size (1277772)
PHP serialized in 0.12110209465 seconds. Size (1955548)
JSON decode in 0.22470498085 seconds
PHP serialized in 0.211947917938 seconds
json_encode() was roughly 80.52% faster than serialize()
unserialize() was roughly 6.02% faster than json_decode()
JSON string was roughly 53.04% smaller than Serialized string

Chúng ta có thể kết luận rằng JSON mã hóa nhanh hơn và dẫn đến một chuỗi nhỏ hơn, nhưng unserialize sẽ nhanh hơn để giải mã chuỗi.


6
Tôi không biết tại sao mọi người luôn kiểm tra hiệu suất với bộ dữ liệu nhỏ như vậy. Làm điều đó bạn có tất cả các chi phí mà thêm lỗi vào kết quả của bạn. Và nếu mọi người quan tâm đến hiệu suất thì có lẽ vì họ có một bộ dữ liệu rất lớn, bởi vì không có điểm nào đạt được một giây vi mô.
Yann Sagon

1
Tôi thường xuyên lặp đi lặp lại qua nhiều bộ dữ liệu nhỏ. Với hàng trăm bộ dữ liệu nhỏ, việc đạt được 1mS cho mỗi người vẫn còn thú vị.
Teson

@YannSagon Ngay cả với các bộ dữ liệu nhỏ cũng có ý nghĩa để thực hiện kiểm tra hiệu suất. Làm thế nào bạn nên biết trước khi thử nghiệm nếu nó chỉ khoảng một micro giây?
Adam

17

Nếu bạn đang lưu trữ thông tin mà cuối cùng bạn sẽ muốn "bao gồm" vào thời điểm muộn hơn, bạn có thể muốn thử sử dụng var_export . Bằng cách đó, bạn chỉ thực hiện cú đánh trong "tuần tự hóa" chứ không phải trong "không xác định".


Đây có lẽ là cách nhanh nhất có thể. Tôi đã viết một ví dụ trên SO "PHP - tuần tự hóa nhanh /
hủy kích hoạt

12

Tôi đã tăng cường kiểm tra để bao gồm hiệu suất không xác định. Đây là những con số tôi nhận được.

Serialize

JSON encoded in 2.5738489627838 seconds
PHP serialized in 5.2861361503601 seconds
Serialize: json_encode() was roughly 105.38% faster than serialize()


Unserialize

JSON decode in 10.915472984314 seconds
PHP unserialized in 7.6223039627075 seconds
Unserialize: unserialize() was roughly 43.20% faster than json_decode() 

Vì vậy, json dường như nhanh hơn để mã hóa nhưng chậm giải mã. Vì vậy, nó có thể phụ thuộc vào ứng dụng của bạn và những gì bạn mong đợi để làm nhiều nhất.


9

Chủ đề thực sự hay và sau khi đọc một vài câu trả lời, tôi muốn chia sẻ thí nghiệm của mình về chủ đề này.

Tôi có một trường hợp sử dụng trong đó một số bảng "khổng lồ" cần được truy vấn gần như mỗi lần tôi nói chuyện với cơ sở dữ liệu (đừng hỏi tại sao, chỉ là sự thật). Hệ thống bộ đệm cơ sở dữ liệu không phù hợp vì nó sẽ không lưu trữ các yêu cầu khác nhau, vì vậy tôi nghĩ về các hệ thống bộ đệm php.

Tôi đã thử apcunhưng nó không phù hợp với nhu cầu, bộ nhớ không đủ tin cậy trong trường hợp này. Bước tiếp theo là lưu trữ vào một tệp có tuần tự hóa.

Bảng có 14355 mục với 18 cột, đó là các bài kiểm tra và số liệu thống kê của tôi về việc đọc bộ đệm được tuần tự hóa:

JSON:

Như bạn đã nói, sự bất tiện lớn với json_encode/ json_decodelà nó biến đổi mọi thứ thành một StdClassthể hiện (hoặc Object). Nếu bạn cần lặp nó, chuyển đổi nó thành một mảng là điều bạn có thể làm, và vâng, nó sẽ tăng thời gian chuyển đổi

thời gian trung bình: 780,2 ms; sử dụng bộ nhớ: 41,5 MB; kích thước tệp bộ nhớ cache: 3,8 MB

Msgpack

@hutch đề cập đến gói tin . Trang web đẹp. Chúng ta hãy thử xem?

thời gian trung bình: 497 ms; sử dụng bộ nhớ: 32MB; kích thước tệp bộ nhớ cache: 2,8 MB

Điều đó tốt hơn, nhưng đòi hỏi một phần mở rộng mới; biên dịch đôi khi sợ mọi người ...

IgBinary

@GingerDog đề cập đến igbinary . Lưu ý rằng tôi đã đặt igbinary.compact_strings=Offvì tôi quan tâm nhiều hơn đến việc đọc hiệu suất hơn kích thước tệp.

thời gian trung bình: 411,4 ms; sử dụng bộ nhớ: 36,75 MB; kích thước tệp bộ nhớ cache: 3,3 MB

Tốt hơn gói tin nhắn. Tuy nhiên, cái này đòi hỏi phải biên dịch quá.

serialize/unserialize

thời gian trung bình: 477,2 ms; sử dụng bộ nhớ: 36,25MB; kích thước tệp bộ nhớ cache: 5,9 MB

Hiệu suất tốt hơn JSON, mảng càng lớn, chậm hơn json_decode, nhưng bạn đã làm được điều đó.

Những phần mở rộng bên ngoài đang thu hẹp kích thước tệp và có vẻ tuyệt vời trên giấy. Số không nói dối *. Điểm biên dịch một phần mở rộng là gì nếu bạn nhận được gần như cùng kết quả mà bạn có với một hàm PHP tiêu chuẩn?

Chúng tôi cũng có thể suy luận rằng tùy thuộc vào nhu cầu của bạn, bạn sẽ chọn một cái gì đó khác với người khác:

  • IgBinary thực sự tốt và hoạt động tốt hơn MsgPack
  • Msgpack tốt hơn trong việc nén dữ liệu của bạn (lưu ý rằng tôi đã không thử tùy chọn igbinary compact.opes).
  • Không muốn biên dịch? Sử dụng tiêu chuẩn.

Đó là nó, một phương pháp so sánh nối tiếp khác để giúp bạn chọn một phương pháp!

* Đã thử nghiệm với PHPUnit 3.7.31, php 5.5.10 - chỉ giải mã với CPU lõi cứng tiêu chuẩn và CPU lõi kép cũ - số trung bình trên 10 bài kiểm tra trường hợp sử dụng giống nhau, số liệu thống kê của bạn có thể khác


Tại sao không chuyển cờ sang json_decode để buộc trả về mảng?
Alex Yaroshevich

Bởi vì nó chậm. Tôi đã không kiểm tra điều này nhưng tôi nghĩ rằng chỉ cần buộc thay đổi kiểu từ php là nhanh hơn.
Soyuka

Tôi chỉ biết rằng việc tạo mảng nhanh hơn nhiều so với các đối tượng trong php.
Alex Yaroshevich

Vì vậy, bạn đang nói về json_decode($object, true)cơ bản, nó sẽ làm tương tự (array) json_decode($object)nhưng theo cách đệ quy để đó sẽ là cùng một hành vi và nó sẽ có chi phí đáng kể trong cả hai trường hợp. Lưu ý rằng tôi chưa kiểm tra hiệu suất khác nhau giữa StdClassarraynhưng đó không thực sự là vấn đề ở đây.
Soyuka

Tôi chắc chắn đó là một chi phí khác bởi vì nó được thực hiện ở cấp độ thấp hơn mà không có đối tượng.
Alex Yaroshevich

8

Có vẻ như serialization là thứ tôi sẽ sử dụng vì 2 lý do:

  • Ai đó đã chỉ ra rằng unserialize nhanh hơn json_decode và trường hợp 'đọc' nghe có vẻ có khả năng cao hơn trường hợp 'ghi'.

  • Tôi đã gặp sự cố với json_encode khi có chuỗi có ký tự UTF-8 không hợp lệ. Khi điều đó xảy ra, chuỗi kết thúc trống rỗng gây mất thông tin.


bạn có thể vui lòng giải thích điểm cuối cùng của bạn bằng một ví dụ
Naveen Saroye

6

Tôi đã kiểm tra điều này rất kỹ lưỡng trên một hàm băm khá phức tạp, được lồng nhẹ với tất cả các loại dữ liệu trong đó (chuỗi, NULL, số nguyên) và serialize / unserialize kết thúc nhanh hơn nhiều so với json_encode / json_decode.

Lợi thế duy nhất mà json có trong các thử nghiệm của tôi là kích thước 'đóng gói' nhỏ hơn.

Chúng được thực hiện theo PHP 5.3.3, cho tôi biết nếu bạn muốn biết thêm chi tiết.

Dưới đây là kết quả kiểm tra sau đó mã để sản xuất chúng. Tôi không thể cung cấp dữ liệu thử nghiệm vì nó tiết lộ thông tin mà tôi không thể để ra ngoài tự nhiên.

JSON encoded in 2.23700618744 seconds
PHP serialized in 1.3434419632 seconds
JSON decoded in 4.0405561924 seconds
PHP unserialized in 1.39393305779 seconds

serialized size : 14549
json_encode size : 11520
serialize() was roughly 66.51% faster than json_encode()
unserialize() was roughly 189.87% faster than json_decode()
json_encode() string was roughly 26.29% smaller than serialize()

//  Time json encoding
$start = microtime( true );
for($i = 0; $i < 10000; $i++) {
    json_encode( $test );
}
$jsonTime = microtime( true ) - $start;
echo "JSON encoded in $jsonTime seconds<br>";

//  Time serialization
$start = microtime( true );
for($i = 0; $i < 10000; $i++) {
    serialize( $test );
}
$serializeTime = microtime( true ) - $start;
echo "PHP serialized in $serializeTime seconds<br>";

//  Time json decoding
$test2 = json_encode( $test );
$start = microtime( true );
for($i = 0; $i < 10000; $i++) {
    json_decode( $test2 );
}
$jsonDecodeTime = microtime( true ) - $start;
echo "JSON decoded in $jsonDecodeTime seconds<br>";

//  Time deserialization
$test2 = serialize( $test );
$start = microtime( true );
for($i = 0; $i < 10000; $i++) {
    unserialize( $test2 );
}
$unserializeTime = microtime( true ) - $start;
echo "PHP unserialized in $unserializeTime seconds<br>";

$jsonSize = strlen(json_encode( $test ));
$phpSize = strlen(serialize( $test ));

echo "<p>serialized size : " . strlen(serialize( $test )) . "<br>";
echo "json_encode size : " . strlen(json_encode( $test )) . "<br></p>";

//  Compare them
if ( $jsonTime < $serializeTime )
{
    echo "json_encode() was roughly " . number_format( ($serializeTime / $jsonTime - 1 ) * 100, 2 ) . "% faster than serialize()";
}
else if ( $serializeTime < $jsonTime )
{
    echo "serialize() was roughly " . number_format( ($jsonTime / $serializeTime - 1 ) * 100, 2 ) . "% faster than json_encode()";
} else {
    echo 'Unpossible!';
}
    echo '<BR>';

//  Compare them
if ( $jsonDecodeTime < $unserializeTime )
{
    echo "json_decode() was roughly " . number_format( ($unserializeTime / $jsonDecodeTime - 1 ) * 100, 2 ) . "% faster than unserialize()";
}
else if ( $unserializeTime < $jsonDecodeTime )
{
    echo "unserialize() was roughly " . number_format( ($jsonDecodeTime / $unserializeTime - 1 ) * 100, 2 ) . "% faster than json_decode()";
} else {
    echo 'Unpossible!';
}
    echo '<BR>';
//  Compare them
if ( $jsonSize < $phpSize )
{
    echo "json_encode() string was roughly " . number_format( ($phpSize / $jsonSize - 1 ) * 100, 2 ) . "% smaller than serialize()";
}
else if ( $phpSize < $jsonSize )
{
    echo "serialize() string was roughly " . number_format( ($jsonSize / $phpSize - 1 ) * 100, 2 ) . "% smaller than json_encode()";
} else {
    echo 'Unpossible!';
}

Tôi vừa thực hiện một thử nghiệm tương tự với PHP 5.4.12 và nhận thấy kết quả tương tự: {un,} serialization nhanh hơn. Dữ liệu của tôi là băm sâu 3 cấp độ lồng nhau (900k nối tiếp).
Bọ Cạp

6

Tôi đã làm một điểm chuẩn nhỏ là tốt. Kết quả của tôi là như nhau. Nhưng tôi cần hiệu suất giải mã. Nơi tôi nhận thấy, giống như một vài người ở trên cũng nói, unserializenhanh hơn json_decode. unserializemất khoảng 60-70% json_decodethời gian. Vì vậy, kết luận khá đơn giản: Khi bạn cần hiệu suất trong mã hóa, hãy sử dụngjson_encode , khi bạn cần hiệu suất khi giải mã, hãy sử dụng unserialize. Bởi vì bạn không thể hợp nhất hai chức năng mà bạn phải tạo ra một lựa chọn mà bạn cần hiệu suất cao hơn.

Điểm chuẩn của tôi trong giả:

  • Xác định mảng $ Array với một vài khóa và giá trị ngẫu nhiên
  • cho x <100; x ++; tuần tự hóa và json_encode một mảng_rand của $ Array
  • cho y <1000; y ++; json_decode chuỗi mã hóa json - thời gian calc
  • cho y <1000; y ++; hủy kích hoạt chuỗi nối tiếp - thời gian calc
  • lặp lại kết quả nhanh hơn

Trên avarage: unserialize giành được 96 lần trên 4 lần json_decode. Với một khoảng cách khoảng 1,5ms trên 2,5ms.


3

Trước khi bạn đưa ra quyết định cuối cùng, hãy lưu ý rằng định dạng JSON không an toàn cho các mảng kết hợp - json_decode()thay vào đó sẽ trả về chúng dưới dạng đối tượng:

$config = array(
    'Frodo'   => 'hobbit',
    'Gimli'   => 'dwarf',
    'Gandalf' => 'wizard',
    );
print_r($config);
print_r(json_decode(json_encode($config)));

Đầu ra là:

Array
(
    [Frodo] => hobbit
    [Gimli] => dwarf
    [Gandalf] => wizard
)
stdClass Object
(
    [Frodo] => hobbit
    [Gimli] => dwarf
    [Gandalf] => wizard
)

Thật vậy, bạn đã đúng. Ý tôi là, đó ký hiệu đối tượng Javascript ! Rất may, nếu bạn biết rằng những gì bạn đã mã hóa bằng cách sử dụng json_encodemột mảng kết hợp, bạn có thể dễ dàng buộc nó trở lại thành một mảng như vậy: $json = json_encode($some_assoc_array); $back_to_array = (array)json_decode($json);Cũng tốt để lưu ý rằng bạn có thể truy cập các đối tượng giống như các mảng trong PHP trong một kịch bản điển hình, người ta thậm chí sẽ không biết sự khác biệt. Điểm tốt mặc dù!
KyleFarris

30
@toomuchphp, xin lỗi nhưng bạn sai rồi. Có một tham số thứ hai cho json_decode 'bool $ assoc = false' làm cho json_decode tạo ra một mảng. @KyleFarris, điều này cũng sẽ nhanh hơn so với việc sử dụng typecast để mảng.
janpio

Câu trả lời không đúng. khi sử dụng true như tham số thứ hai của hàm, json_decode () sẽ trả về các mảng kết hợp thay vì các đối tượng.
Marvin Saldinger 7/07/2015

3

Đầu tiên, tôi đã thay đổi tập lệnh để thực hiện thêm một số điểm chuẩn (và cũng thực hiện 1000 lần chạy thay vì chỉ 1):

<?php

ini_set('display_errors', 1);
error_reporting(E_ALL);

// Make a big, honkin test array
// You may need to adjust this depth to avoid memory limit errors
$testArray = fillArray(0, 5);

$totalJsonTime = 0;
$totalSerializeTime = 0;
$totalJsonWins = 0;

for ($i = 0; $i < 1000; $i++) {
    // Time json encoding
    $start = microtime(true);
    $json = json_encode($testArray);
    $jsonTime = microtime(true) - $start;
    $totalJsonTime += $jsonTime;

    // Time serialization
    $start = microtime(true);
    $serial = serialize($testArray);
    $serializeTime = microtime(true) - $start;
    $totalSerializeTime += $serializeTime;

    if ($jsonTime < $serializeTime) {
        $totalJsonWins++;
    }
}

$totalSerializeWins = 1000 - $totalJsonWins;

// Compare them
if ($totalJsonTime < $totalSerializeTime) {
    printf("json_encode() (wins: $totalJsonWins) was roughly %01.2f%% faster than serialize()\n", ($totalSerializeTime / $totalJsonTime - 1) * 100);
} else {
    printf("serialize() (wins: $totalSerializeWins) was roughly %01.2f%% faster than json_encode()\n", ($totalJsonTime / $totalSerializeTime - 1) * 100);
}

$totalJsonTime = 0;
$totalJson2Time = 0;
$totalSerializeTime = 0;
$totalJsonWins = 0;

for ($i = 0; $i < 1000; $i++) {
    // Time json decoding
    $start = microtime(true);
    $orig = json_decode($json, true);
    $jsonTime = microtime(true) - $start;
    $totalJsonTime += $jsonTime;

    $start = microtime(true);
    $origObj = json_decode($json);
    $jsonTime2 = microtime(true) - $start;
    $totalJson2Time += $jsonTime2;

    // Time serialization
    $start = microtime(true);
    $unserial = unserialize($serial);
    $serializeTime = microtime(true) - $start;
    $totalSerializeTime += $serializeTime;

    if ($jsonTime < $serializeTime) {
        $totalJsonWins++;
    }
}

$totalSerializeWins = 1000 - $totalJsonWins;


// Compare them
if ($totalJsonTime < $totalSerializeTime) {
    printf("json_decode() was roughly %01.2f%% faster than unserialize()\n", ($totalSerializeTime / $totalJsonTime - 1) * 100);
} else {
    printf("unserialize() (wins: $totalSerializeWins) was roughly %01.2f%% faster than json_decode()\n", ($totalJsonTime / $totalSerializeTime - 1) * 100);
}

// Compare them
if ($totalJson2Time < $totalSerializeTime) {
    printf("json_decode() was roughly %01.2f%% faster than unserialize()\n", ($totalSerializeTime / $totalJson2Time - 1) * 100);
} else {
    printf("unserialize() (wins: $totalSerializeWins) was roughly %01.2f%% faster than array json_decode()\n", ($totalJson2Time / $totalSerializeTime - 1) * 100);
}

function fillArray( $depth, $max ) {
    static $seed;
    if (is_null($seed)) {
        $seed = array('a', 2, 'c', 4, 'e', 6, 'g', 8, 'i', 10);
    }
    if ($depth < $max) {
        $node = array();
        foreach ($seed as $key) {
            $node[$key] = fillArray($depth + 1, $max);
        }
        return $node;
    }
    return 'empty';
}

Tôi đã sử dụng bản dựng này của PHP 7:

PHP 7.0.14 (cli) (được xây dựng: 18 tháng 1 năm 2017 19:13:23) (NTS) Bản quyền (c) 1997-2016 Nhóm Zend Engine v3.0.0, Bản quyền (c) 1998-2016 Zend Technologies với Zend OPcache v7.0.14, Bản quyền (c) 1999-2016, bởi Zend Technologies

Và kết quả của tôi là:

serialize () (thắng: 999) nhanh hơn khoảng 10,98% so với json_encode () unserialize () (thắng: 987) nhanh hơn khoảng 33,26% so với json_decode () unserialize () (thắng: 987) nhanh hơn khoảng 48,35% so với mảng json_decode ()

Vì vậy, rõ ràng , serialize / unserialize là phương pháp nhanh nhất , trong khi json_encode / decode là phương tiện di động nhất.

Nếu bạn xem xét một kịch bản trong đó bạn đọc / ghi dữ liệu được xê-ri hóa gấp 10 lần hoặc thường xuyên hơn bạn cần gửi đến hoặc nhận từ một hệ thống không phải là PHP, bạn VẪN nên sử dụng serialize / unserialize và sử dụng json_encode hoặc json_decode trước khi tuần tự hóa về mặt thời gian.


2

Kiểm tra kết quả tại đây (xin lỗi vì vụ hack đưa mã PHP vào hộp mã JS):

http://jsfiddle.net/newms87/h3b0a0ha/embedded/result/

KẾT QUẢ: serialize()unserialize()cả hai đều nhanh hơn đáng kể trong PHP 5.4 trên các mảng có kích thước khác nhau.

Tôi đã tạo một kịch bản thử nghiệm trên dữ liệu trong thế giới thực để so sánh json_encode với serialize và json_decode với unserialize. Thử nghiệm đã được chạy trên hệ thống bộ nhớ đệm của một trang web thương mại điện tử sản xuất. Nó chỉ đơn giản là lấy dữ liệu đã có trong bộ đệm và kiểm tra thời gian để mã hóa / giải mã (hoặc tuần tự hóa / hủy kích hoạt) tất cả dữ liệu và tôi đặt nó vào một bảng dễ nhìn.

Tôi đã chạy nó trên máy chủ lưu trữ chia sẻ PHP 5.4.

Các kết quả đã rất kết luận rằng đối với các tập dữ liệu lớn đến nhỏ này tuần tự hóa và không xác định là những người chiến thắng rõ ràng. Đặc biệt đối với trường hợp sử dụng của tôi, json_decode và unserialize là quan trọng nhất đối với hệ thống bộ đệm. Unserialize gần như là một người chiến thắng phổ biến ở đây. Nó thường nhanh gấp 2 đến 4 lần (đôi khi 6 hoặc 7 lần) nhanh như json_decode.

Thật thú vị khi lưu ý sự khác biệt trong kết quả từ @ peter-bailey.

Đây là mã PHP được sử dụng để tạo kết quả:

<?php

ini_set('display_errors', 1);
error_reporting(E_ALL);

function _count_depth($array)
{
    $count     = 0;
    $max_depth = 0;
    foreach ($array as $a) {
        if (is_array($a)) {
            list($cnt, $depth) = _count_depth($a);
            $count += $cnt;
            $max_depth = max($max_depth, $depth);
        } else {
            $count++;
        }
    }

    return array(
        $count,
        $max_depth + 1,
    );
}

function run_test($file)
{
    $memory     = memory_get_usage();
    $test_array = unserialize(file_get_contents($file));
    $memory     = round((memory_get_usage() - $memory) / 1024, 2);

    if (empty($test_array) || !is_array($test_array)) {
        return;
    }

    list($count, $depth) = _count_depth($test_array);

    //JSON encode test
    $start            = microtime(true);
    $json_encoded     = json_encode($test_array);
    $json_encode_time = microtime(true) - $start;

    //JSON decode test
    $start = microtime(true);
    json_decode($json_encoded);
    $json_decode_time = microtime(true) - $start;

    //serialize test
    $start          = microtime(true);
    $serialized     = serialize($test_array);
    $serialize_time = microtime(true) - $start;

    //unserialize test
    $start = microtime(true);
    unserialize($serialized);
    $unserialize_time = microtime(true) - $start;

    return array(
        'Name'                   => basename($file),
        'json_encode() Time (s)' => $json_encode_time,
        'json_decode() Time (s)' => $json_decode_time,
        'serialize() Time (s)'   => $serialize_time,
        'unserialize() Time (s)' => $unserialize_time,
        'Elements'               => $count,
        'Memory (KB)'            => $memory,
        'Max Depth'              => $depth,
        'json_encode() Win'      => ($json_encode_time > 0 && $json_encode_time < $serialize_time) ? number_format(($serialize_time / $json_encode_time - 1) * 100, 2) : '',
        'serialize() Win'        => ($serialize_time > 0 && $serialize_time < $json_encode_time) ? number_format(($json_encode_time / $serialize_time - 1) * 100, 2) : '',
        'json_decode() Win'      => ($json_decode_time > 0 && $json_decode_time < $serialize_time) ? number_format(($serialize_time / $json_decode_time - 1) * 100, 2) : '',
        'unserialize() Win'      => ($unserialize_time > 0 && $unserialize_time < $json_decode_time) ? number_format(($json_decode_time / $unserialize_time - 1) * 100, 2) : '',
    );
}

$files = glob(dirname(__FILE__) . '/system/cache/*');

$data = array();

foreach ($files as $file) {
    if (is_file($file)) {
        $result = run_test($file);

        if ($result) {
            $data[] = $result;
        }
    }
}

uasort($data, function ($a, $b) {
    return $a['Memory (KB)'] < $b['Memory (KB)'];
});

$fields = array_keys($data[0]);
?>

<table>
    <thead>
    <tr>
        <?php foreach ($fields as $f) { ?>
            <td style="text-align: center; border:1px solid black;padding: 4px 8px;font-weight:bold;font-size:1.1em"><?= $f; ?></td>
        <?php } ?>
    </tr>
    </thead>

    <tbody>
    <?php foreach ($data as $d) { ?>
        <tr>
            <?php foreach ($d as $key => $value) { ?>
                <?php $is_win = strpos($key, 'Win'); ?>
                <?php $color = ($is_win && $value) ? 'color: green;font-weight:bold;' : ''; ?>
                <td style="text-align: center; vertical-align: middle; padding: 3px 6px; border: 1px solid gray; <?= $color; ?>"><?= $value . (($is_win && $value) ? '%' : ''); ?></td>
            <?php } ?>
        </tr>
    <?php } ?>
    </tbody>
</table>

1

chỉ là một fyi - nếu bạn muốn tuần tự hóa dữ liệu của mình thành thứ gì đó dễ đọc và dễ hiểu như JSON nhưng với độ nén cao hơn và hiệu năng cao hơn, bạn nên kiểm tra gói tin.


2
Nếu đó chỉ là một fyi, tốt hơn hết bạn nên bình luận.
Technophyle

0

JSON sẽ tốt hơn nếu bạn muốn sao lưu dữ liệu và khôi phục nó trên một máy khác hoặc qua FTP.

Ví dụ: với tuần tự hóa nếu bạn lưu trữ dữ liệu trên máy chủ Windows, hãy tải xuống qua FTP và khôi phục dữ liệu trên Linux, nó không thể hoạt động được nữa do mã hóa lại trình duyệt, bởi vì tuần tự hóa lưu trữ độ dài của chuỗi và trong Unicode > UTF-8 chuyển mã một số charachter 1 byte có thể trở thành 2 byte dài khiến thuật toán bị sập.


0

THX - cho mã điểm chuẩn này:

Kết quả của tôi trên mảng tôi sử dụng cho cấu hình như Fallows: JSON mã hóa trong ,0031511783599854 giây
PHP đăng trên 0,0037961006164551 giây
json_encode()được khoảng 20,47% nhanh hơn so với serialize() JSON mã hóa trong ,0070841312408447 giây
PHP đăng trên 0,0035839080810547 giây
unserialize()được khoảng 97,66% nhanh hơnjson_encode()

Vì vậy - kiểm tra nó trên dữ liệu của riêng bạn.


Ý bạn là json_decode () trong "unserialize () nhanh hơn khoảng 97,66% so với json_encode ()", đúng không?
Meezaan-ud-Din

0

Nếu để tóm tắt những gì mọi người nói ở đây, json_decode / encode có vẻ nhanh hơn serialization / unserialize NHƯNG Nếu bạn thực hiện var_dump, loại đối tượng được tuần tự hóa được thay đổi. Nếu vì lý do nào đó bạn muốn giữ kiểu, hãy đi theo tuần tự!

(thử ví dụ stdClass vs mảng)

serialize / unserialize:

Array cache:
array (size=2)
  'a' => string '1' (length=1)
  'b' => int 2
Object cache:
object(stdClass)[8]
  public 'field1' => int 123
This cache:
object(Controller\Test)[8]
  protected 'view' => 

json mã hóa / giải mã

Array cache:
object(stdClass)[7]
  public 'a' => string '1' (length=1)
  public 'b' => int 2
Object cache:
object(stdClass)[8]
  public 'field1' => int 123
This cache:
object(stdClass)[8]

Như bạn có thể thấy json_encode / giải mã chuyển đổi tất cả thành stdClass, điều đó không tốt, thông tin đối tượng bị mất ... Vì vậy, hãy quyết định dựa trên nhu cầu, đặc biệt nếu đó không chỉ là mảng ...


Chỉ cần một lưu ý: Hầu hết các câu trả lời khác nói rằng serialization / unserialize nhanh hơn.
Ecker00

-3

Tôi sẽ đề nghị bạn sử dụng Super Cache, đây là một cơ chế bộ đệm tệp không sử dụng json_encodehoặc serialize. Nó rất đơn giản để sử dụng và thực sự nhanh so với các cơ chế PHP Cache khác.

https://packagist.org/packages/smart-php/super-cache

Ví dụ:

<?php
require __DIR__.'/vendor/autoload.php';
use SuperCache\SuperCache as sCache;

//Saving cache value with a key
// sCache::cache('<key>')->set('<value>');
sCache::cache('myKey')->set('Key_value');

//Retrieving cache value with a key
echo sCache::cache('myKey')->get();
?>

-1. Mặc dù nó có thể là một giải pháp tốt hơn, nhưng không có phần nào trong câu trả lời này thực sự trả lời câu hỏi của OP. Trong tương lai, có lẽ hãy thử trả lời câu hỏi nhưng để lại một gợi ý ở phía dưới rằng một giải pháp thay thế có thể đáng để điều tra.
starbeamrainbowlabs
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.