วิธีที่ต้องการในการเก็บอาร์เรย์ PHP (json_encode เทียบกับอันดับ)


609

ฉันต้องการจัดเก็บอาเรย์เชื่อมโยงหลายมิติข้อมูลในไฟล์แฟล็ตเพื่อการแคช ฉันอาจต้องแปลงเป็น JSON เป็นครั้งคราวเพื่อใช้ในเว็บแอปของฉัน แต่ส่วนใหญ่ฉันจะใช้อาร์เรย์โดยตรงใน PHP

จะมีประสิทธิภาพมากกว่าหรือไม่ในการจัดเก็บอาร์เรย์เป็น JSON หรือเป็นอาร์เรย์ PHP ต่อเนื่องในไฟล์ข้อความนี้ ฉันได้ดูไปรอบ ๆ และดูเหมือนว่าใน PHP เวอร์ชันล่าสุด (5.3) json_decodeนั้นเร็วกว่าจริงunserialize

ขณะนี้ฉันเอนตัวไปที่การจัดเก็บอาร์เรย์เป็น JSON เพราะฉันรู้สึกว่ามันง่ายต่อการอ่านโดยมนุษย์ถ้าจำเป็นมันสามารถใช้ได้ทั้ง PHP และ JavaScript ด้วยความพยายามน้อยมากและจากสิ่งที่ฉันอ่านมันอาจจะเป็น เร็วกว่าในการถอดรหัส (ไม่แน่ใจเกี่ยวกับการเข้ารหัส)

ไม่มีใครรู้ถึงข้อผิดพลาดใด ๆ ? ทุกคนมีเกณฑ์มาตรฐานที่ดีในการแสดงผลประโยชน์ด้านประสิทธิภาพของวิธีใด

คำตอบ:


563

ขึ้นอยู่กับความสำคัญของคุณ

หากประสิทธิภาพการขับขี่นั้นเป็นคุณสมบัติการขับขี่แบบสัมบูรณ์คุณก็ควรใช้รถที่เร็วที่สุด เพียงให้แน่ใจว่าคุณมีความเข้าใจที่แตกต่างก่อนที่จะทำการเลือก

  • ไม่เหมือนกับที่serialize()คุณต้องการเพิ่มพารามิเตอร์พิเศษเพื่อไม่ให้แตะอักขระ UTF-8: json_encode($array, JSON_UNESCAPED_UNICODE) (ไม่เช่นนั้นจะแปลงอักขระ UTF-8 เป็น Unicode escape ตามลำดับ)
  • JSON จะไม่มีหน่วยความจำว่าคลาสดั้งเดิมของวัตถุนั้นคืออะไร (จะถูกเรียกคืนเป็นอินสแตนซ์ของ stdClass เสมอ)
  • คุณไม่สามารถยกระดับ__sleep()และใช้__wakeup()JSON ได้
  • โดยค่าเริ่มต้นคุณสมบัติสาธารณะเท่านั้นที่จะต่อเนื่องกับ JSON (ในPHP>=5.4คุณสามารถใช้JsonSerializableเพื่อเปลี่ยนพฤติกรรมนี้)
  • JSON พกพาสะดวกมากขึ้น

และอาจมีความแตกต่างอื่น ๆ อีกเล็กน้อยที่ฉันนึกไม่ออกตอนนี้

การทดสอบความเร็วอย่างง่ายเพื่อเปรียบเทียบทั้งสอง

<?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 แปลงอักขระ UTF-8 เป็น Unicode escape" ไม่จำเป็นต้องเป็นจริง: JSON_UNESCAPED_UNICODEตอนนี้เรามี
TRiG

32
ที่นี่เราเกือบ 5 ปีต่อมาและฉันทำการทดสอบอีกครั้ง (แค่json_encode) และมันเฉลี่ยโดยเร็วกว่าตอนนี้ประมาณ 131% ดังนั้นจะต้องมีการปรับปรุงที่ดีงามในฟังก์ชั่นนั้นใน 5.4.x มากกว่า 5.3.x โดยเฉพาะฉันใช้ 5.4.24 บน CentOS 6 ดังนั้นคุณต้อง JSON !!
KyleFarris

8
ในกรณีของฉันเราเข้ารหัสและถอดรหัสครั้งเดียวเป็นจำนวนมากดังนั้นเรา benchmarked json_decode VS unserialize และผลเป็น JSON dcoded ใน 0.06662392616272 วินาที <br> PHP unserialized ใน 0.093269109725952 วินาที <br> json_decode () เป็นประมาณ 39.99% เร็วกว่า unserialize ()
AMB

21
สิ่งที่น่าสนใจ: หากคุณเรียกใช้รหัสนี้ใน3v4l.orgการพัฒนา PHP7 รุ่นใหม่ล่าสุดรันการทำให้เป็นอันดับเร็วกว่า json_encode: "serialize () นั้นเร็วกว่า 76.53% เร็วกว่า json_encode ()"
marcvangend

21
2017, PHP 7.1 และserialize() was roughly 35.04% faster than json_encode()
Elias Soares

239

JSONนั้นง่ายกว่าและเร็วกว่ารูปแบบอนุกรมของ PHP และควรใช้เว้นแต่ :

  • คุณกำลังจัดเก็บอาร์เรย์ที่ซ้อนกันอย่างลึกล้ำ json_decode():: "ฟังก์ชั่นนี้จะคืนค่าเท็จหากข้อมูลที่เข้ารหัสของ JSON นั้นลึกกว่า 127 องค์ประกอบ"
  • คุณกำลังจัดเก็บวัตถุที่ต้องยกเลิกการตั้งค่าเป็นคลาสที่ถูกต้อง
  • คุณกำลังโต้ตอบกับ PHP เวอร์ชันเก่าที่ไม่สนับสนุน json_decode

12
คำตอบที่ดี ฮ่าฮ่าระดับ 127 ลึกดูเหมือนว่าบ้า โชคดีที่ฉันไปได้แค่ 2-3 คนเท่านั้น คุณมีข้อมูลใด ๆ เพื่อสำรองความจริงที่ว่า json_decode / json_encode เร็วกว่ายกเลิกการตั้งค่า / ซีเรียลไลซ์หรือไม่?
KyleFarris

1
ฉันทำการทดสอบเมื่อไม่นานมานี้และ json ออกมาเร็วกว่านี้ - ฉันไม่มีข้อมูลอีกต่อไป
เกร็ก

47
"5.3.0 เพิ่มความลึกที่เป็นทางเลือกความลึกของการเรียกซ้ำเริ่มต้นเพิ่มขึ้นจาก 128 เป็น 512"
giorgio79

4
ฉันจะเพิ่มอีกหนึ่งรายการในรายการด้านบน: json_encode () ไม่ควรใช้หากข้อมูลของคุณอาจมีลำดับ UTF-8 ที่ไม่ถูกต้อง มันเพียงแค่ส่งกลับเท็จสำหรับข้อมูลดังกล่าว ลองตัวอย่างเช่น: var_dump (json_encode ("\ xEF \ xEF"));
pako

2
มันไม่เป็นความจริงเลยที่มันเร็วกว่าทั่วไป หากคุณมีอาร์เรย์ขนาดเล็กที่มีประมาณ ~ 500 รายการดังนั้นการยกเลิกการ unserialize / serialize จะเร็วกว่า 200-400% จากนั้น json_decode / json_encode (PHP 5.6.19)
อดัม

59

ผมเคยเขียนบล็อกโพสต์เกี่ยวกับเรื่องนี้" แคช array ขนาดใหญ่: JSON, อันดับหรือ var_export " ในโพสต์นี้จะแสดงว่าซีเรียลไลซ์เป็นตัวเลือกที่ดีที่สุดสำหรับอาร์เรย์ขนาดเล็กถึงขนาดใหญ่ สำหรับอาร์เรย์ที่มีขนาดใหญ่มาก (> 70MB) JSON เป็นตัวเลือกที่ดีกว่า


8
ลิงก์ไม่สามารถใช้ได้อีก
Martin Thoma

1
ขอบคุณฉันได้อัปเดตลิงก์แล้ว แม้ว่าบทความจะมีอายุเกือบ 6 ปีและอาจไม่ถูกต้องสำหรับเวอร์ชัน PHP ปัจจุบัน
Taco

ฉันไม่ได้ทดสอบบางอย่างและทำให้ฟังก์ชั่นที่ง่ายในการทดสอบกับอาร์เรย์ใหญ่ (ฟังก์ชั่นที่ใช้ปีเตอร์เบลีย์สำหรับผู้) json_encode()เป็นเรื่องเกี่ยวกับ80% ถึง 150%ได้เร็วขึ้น (จริงๆจะขึ้นและลงที่นั่น) กว่าserialize()มีประมาณ 300 ซ้ำ แต่เมื่อใช้อาร์เรย์ขนาดเล็กลง ( array("teams" => array(1 => array(4 arrays of players), 2 => array(4 arrays of players)))) ฉันทำการทดสอบซ้ำ750,000ครั้งและเร็วขึ้นserialize()ประมาณ6% ถึง 10% ฟังก์ชั่นของฉันใช้เวลาเฉลี่ยสำหรับการคำนวณซ้ำทั้งหมดและทำการเปรียบเทียบ ฉันอาจโพสต์ไว้ที่นี่เป็นหนึ่งในคำตอบ
MiChAeLoKGB

ถ้าข้อมูลถูกใช้โดย PHP เท่านั้น var_export ก็เป็นของฉัน เพียงแค่ต้องระมัดระวังกับข้อผิดพลาดทางไวยากรณ์ที่เป็นไปได้ในการคิดรวม
Gfra54

3
ไม่มีบล็อกอีกต่อไป
popeye

53

คุณอาจสนใจhttps://github.com/phadej/igbinaryซึ่งให้ 'engine' การเรียงลำดับที่แตกต่างกันสำหรับ PHP

ตัวเลข 'ประสิทธิภาพ' แบบสุ่มโดยพลการของฉันโดยใช้ PHP 5.3.5 ในการแสดงแพลตฟอร์ม 64 บิต:

JSON:

  • JSON เข้ารหัสใน 2.180496931076 วินาที
  • JSON ถอดรหัสใน 9.8368630409241 วินาที
  • ขนาด "สตริง" ต่อเนื่อง: 13993

PHP พื้นเมือง:

  • PHP ต่อเนื่องใน 2.9125759601593 วินาที
  • PHP ไม่ตั้งค่าใน 6.4348418712616 วินาที
  • ขนาด "สตริง" ต่อเนื่อง: 20769

Igbinary:

  • รับรางวัล igbinary ต่อเนื่องใน 1.6099879741669 วินาที
  • รับรางวัล igbinrary unserialized ใน 4.7737920284271 วินาที
  • WINขนาด "สตริง" ต่อเนื่อง: 4467

ดังนั้นจึงเร็วกว่าที่จะ igbinary_serialize () และ igbinary_unserialize () และใช้พื้นที่ดิสก์น้อยลง

ฉันใช้รหัส fillArray (0, 3) ข้างต้น แต่ทำให้สตริงของคีย์อาร์เรย์ยาวขึ้น

igbinary สามารถเก็บข้อมูลชนิดเดียวกับที่เป็นอนุกรมดั้งเดิมของ PHP (ดังนั้นจึงไม่มีปัญหากับวัตถุอื่น ๆ ) และคุณสามารถบอก PHP5.3 ให้ใช้สำหรับการจัดการเซสชันถ้าคุณต้องการ

ดูเพิ่มเติมที่http://ilia.ws/files/zendcon_2010_hidden_features.pdf - สไลด์เฉพาะ 14/15/16


25

Y เพิ่งทดสอบอนุกรมและ json เข้ารหัสและถอดรหัสรวมทั้งขนาดที่จะใช้สตริงที่เก็บไว้

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

เราสามารถสรุปได้ว่า JSON เข้ารหัสได้เร็วขึ้นและส่งผลให้สตริงมีขนาดเล็กลง แต่การ unserialize เร็วกว่าในการถอดรหัสสตริง


6
ฉันไม่รู้ว่าทำไมผู้คนยังทำการทดสอบประสิทธิภาพด้วยชุดข้อมูลขนาดเล็กมาก การทำเช่นนั้นคุณมีค่าใช้จ่ายทั้งหมดที่เพิ่มข้อผิดพลาดในผลลัพธ์ของคุณ และถ้าผู้คนสนใจในการแสดงอาจเป็นเพราะพวกเขามีชุดข้อมูลที่มีขนาดใหญ่มากเพราะไม่มีจุดที่จะได้รับไมโครวินาทีหนึ่งครั้ง
Yann Sagon

1
บ่อยครั้งที่ฉันวนซ้ำชุดข้อมูลขนาดเล็กจำนวนมาก ด้วยชุดข้อมูลขนาดเล็กหลายร้อยชุดการเพิ่ม 1mS สำหรับแต่ละชุดยังคงน่าสนใจ
Teson

@YannSagon แม้จะมีชุดข้อมูลขนาดเล็กมันก็สมเหตุสมผลที่จะทำการทดสอบการแสดง คุณจะรู้ได้อย่างไรก่อนการทดสอบถ้ามันมีขนาดเพียงหนึ่งไมโครวินาที
อดัม

17

หากคุณกำลังแคชข้อมูลที่คุณที่สุดจะต้องการที่จะ "รวมถึง" ที่จุดภายหลังในเวลาที่คุณอาจต้องการที่จะลองใช้var_export ด้วยวิธีนี้คุณจะได้รับความนิยมใน "อันดับ" และไม่ได้อยู่ใน "unserialize"


นี่อาจเป็นวิธีที่เร็วที่สุดที่เป็นไปได้ ฉันเขียนตัวอย่างบนดังนั้น "PHP - เร็วเป็นอันดับ / ไม่ระบุ": stackoverflow.com/questions/2545455/ …
dave1010

12

ฉันเพิ่มการทดสอบเพื่อรวมประสิทธิภาพการ unserialization นี่คือตัวเลขที่ฉันได้รับ

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

ดังนั้น json ดูเหมือนจะเร็วกว่าสำหรับการเข้ารหัส แต่ช้าในการถอดรหัส ดังนั้นมันอาจขึ้นอยู่กับใบสมัครของคุณและสิ่งที่คุณคาดหวังว่าจะทำมากที่สุด


9

หัวข้อดีมากจริงๆและหลังจากอ่านคำตอบไม่กี่ข้อฉันต้องการแบ่งปันการทดสอบของฉันในหัวข้อ

ฉันได้รับกรณีการใช้งานซึ่งบางตาราง "ใหญ่" จำเป็นต้องมีการสอบถามเกือบทุกครั้งที่ฉันพูดคุยกับฐานข้อมูล (อย่าถามว่าทำไมเป็นเรื่องจริง ระบบแคชฐานข้อมูลไม่เหมาะสมเพราะมันจะไม่ทำการร้องขอที่แตกต่างกันดังนั้นฉันจึงถามเกี่ยวกับระบบแคช php

ฉันพยายามapcuแต่มันไม่พอดีกับความต้องการหน่วยความจำไม่น่าเชื่อถือเพียงพอในกรณีนี้ ขั้นตอนต่อไปคือการแคชไฟล์ด้วยการทำให้เป็นอนุกรม

ตารางมี 14355 รายการที่มี 18 คอลัมน์นั่นคือการทดสอบและสถิติของฉันในการอ่านแคชแบบอนุกรม:

JSON:

ในขณะที่คุณพูดความไม่สะดวกที่สำคัญกับjson_encode/ json_decodeคือมันเปลี่ยนทุกอย่างเป็นStdClassตัวอย่าง (หรือ Object) หากคุณต้องการวนลูปการแปลงเป็นอาเรย์เป็นสิ่งที่คุณอาจจะทำและใช่มันเป็นการเพิ่มเวลาการแปลง

เวลาเฉลี่ย: 780.2 ms; การใช้หน่วยความจำ: 41.5MB; ขนาดไฟล์แคช: 3.8MB

Msgpack

@hutch กล่าวmsgpack เว็บไซต์สวย มาลองดูกันดีกว่า

เวลาเฉลี่ย: 497 ms; การใช้หน่วยความจำ: 32MB; ขนาดไฟล์แคช: 2.8MB

ดีกว่า แต่ต้องการส่วนขยายใหม่ รวบรวมบางครั้งคนกลัว ...

IgBinary

@GingerDog กล่าวigbinary โปรดทราบว่าฉันได้ตั้งค่าไว้igbinary.compact_strings=Offเพราะฉันสนใจการอ่านมากกว่าขนาดไฟล์

เวลาเฉลี่ย: 411.4 ms; การใช้หน่วยความจำ: 36.75MB; ขนาดไฟล์แคช: 3.3MB

ดีกว่าผงชูรส ถึงอย่างนี้ก็ต้องรวบรวมเช่นกัน

serialize/unserialize

เวลาเฉลี่ย: 477.2 ms; การใช้หน่วยความจำ: 36.25MB; ขนาดไฟล์แคช: 5.9MB

การแสดงที่ดีกว่า JSON ยิ่งอาร์เรย์ยิ่งใหญ่ก็ยิ่งช้าลงjson_decodeแต่คุณก็ยังใหม่อยู่

นามสกุลภายนอกเหล่านั้นแคบลงขนาดไฟล์และดูดีบนกระดาษ ตัวเลขไม่โกหก * การรวบรวมส่วนขยายคืออะไรถ้าคุณได้ผลลัพธ์เกือบเหมือนกันกับที่คุณมีในฟังก์ชั่น PHP มาตรฐาน?

นอกจากนี้เรายังสามารถอนุมานได้ว่าคุณจะเลือกสิ่งที่แตกต่างจากคนอื่น:

  • IgBinary ดีมากและทำงานได้ดีกว่า MsgPack
  • Msgpack ดีกว่าในการบีบอัดข้อมูลของคุณ (โปรดทราบว่าฉันไม่ได้ลองใช้ตัวเลือก igbinary compact.string)
  • ไม่ต้องการที่จะรวบรวม? ใช้มาตรฐาน

นั่นคือวิธีการเปรียบเทียบลำดับอื่นเพื่อช่วยคุณเลือก

* ทดสอบกับ PHPUnit 3.7.31, php 5.5.10 - ถอดรหัสได้เฉพาะกับฮาร์ดไดรฟ์มาตรฐานและซีพียูดูอัลคอร์เก่า - ตัวเลขเฉลี่ยในการทดสอบเคสที่ใช้ 10 กรณีเดียวกันสถิติของคุณอาจแตกต่างกัน


ทำไมไม่ส่งแฟล็กไปที่ json_decode เพื่อบังคับให้อาร์เรย์ที่ส่งคืน?
Alex Yaroshevich

เพราะมันช้า ฉันไม่ได้ทดสอบสิ่งนี้ แต่ฉันคิดว่าการบังคับให้เปลี่ยนประเภทจาก php นั้นเร็วขึ้น
soyuka

ฉันเพิ่งรู้ว่าการสร้างอาร์เรย์เร็วกว่าวัตถุใน PHP
Alex Yaroshevich

ดังนั้นคุณกำลังพูดถึงjson_decode($object, true)โดยทั่วไปมันจะทำแบบเดียวกัน(array) json_decode($object)แต่แบบวนซ้ำเพื่อที่จะเป็นพฤติกรรมเดียวกันและจะมีค่าใช้จ่ายที่สำคัญในทั้งสองกรณี โปรดทราบว่าฉันไม่ได้ทดสอบประสิทธิภาพแตกต่างกันStdClassและarrayนั่นไม่ใช่จุดที่นี่จริงๆ
soyuka

ฉันแน่ใจว่ามันเป็นค่าใช้จ่ายอื่นเพราะมันทำในระดับที่ต่ำกว่าโดยไม่มีวัตถุ
Alex Yaroshevich

8

ดูเหมือนว่าซีเรียลไลซ์เป็นสิ่งที่ฉันจะใช้ด้วยเหตุผล 2 ประการ:

  • มีคนชี้ให้เห็นว่า unserialize เร็วกว่า json_decode และกรณี 'read' ฟังดูน่าจะเป็นมากกว่ากรณี 'write'

  • ฉันมีปัญหากับ json_encode เมื่อมีสตริงที่มีอักขระ UTF-8 ไม่ถูกต้อง เมื่อสิ่งนั้นเกิดขึ้นสตริงจะว่างเปล่าทำให้ข้อมูลสูญหาย


คุณช่วยอธิบายจุดสุดท้ายของคุณด้วยตัวอย่างได้
ไหม

6

ฉันได้ทดสอบสิ่งนี้อย่างละเอียดถี่ถ้วนเกี่ยวกับมัลติแฮชที่ค่อนข้างซับซ้อนซ้อนกันอย่างอ่อน ๆ กับข้อมูลทุกชนิดในนั้น (สตริง, NULL, จำนวนเต็ม), และอนุกรม / unserialize จบลงเร็วกว่า json_encode / json_decode

ข้อได้เปรียบเดียวที่ json มีในการทดสอบของฉันคือขนาดที่เล็กลง

สิ่งเหล่านี้ทำภายใต้ PHP 5.3.3, แจ้งให้เราทราบหากคุณต้องการรายละเอียดเพิ่มเติม

นี่คือผลการทดสอบแล้วรหัสในการผลิตพวกเขา ฉันไม่สามารถให้ข้อมูลการทดสอบได้เพราะมันจะเปิดเผยข้อมูลที่ฉันไม่สามารถปล่อยออกไปได้

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!';
}

ฉันเพิ่งทำการทดสอบที่คล้ายกันกับ PHP 5.4.12 และพบผลลัพธ์ที่คล้ายกัน: {un,} การทำให้เป็นอันดับเร็วขึ้น ข้อมูลของฉันแฮชซ้อนกัน 3 ระดับ (900k ต่อเนื่อง)
sorpigal

6

ฉันทำเกณฑ์มาตรฐานขนาดเล็กเช่นกัน ผลลัพธ์ของฉันเหมือนกัน แต่ฉันต้องการประสิทธิภาพการถอดรหัส ฉันสังเกตเห็นเหมือนไม่กี่คนที่ดังกล่าวข้างต้นเป็นอย่างดีจะเร็วกว่าunserialize ใช้เวลาประมาณ 60-70% ของเวลา ดังนั้นข้อสรุปที่ค่อนข้างง่าย: เมื่อคุณต้องการประสิทธิภาพการทำงานในการเข้ารหัสการใช้งานเมื่อคุณต้องการประสิทธิภาพการทำงานเมื่อถอดรหัสใช้ เพราะคุณไม่สามารถรวมสองฟังก์ชั่นคุณต้องเลือกสถานที่ที่คุณต้องการประสิทธิภาพมากขึ้นjson_decodeunserializejson_decodejson_encodeunserialize

มาตรฐานของฉันในการหลอก:

  • กำหนด $ arr array ด้วยปุ่มและค่าสุ่มสองสามแบบ
  • สำหรับ x <100; x ++; ทำให้เป็นอันดับและ json_encode array_rand ของ $ arr
  • สำหรับ y <1,000; Y ++; json_decode สตริงที่เข้ารหัส json - เวลา calc
  • สำหรับ y <1,000; Y ++; unserialize สตริงที่ทำให้เป็นอนุกรม - เวลาคำนวณ
  • สะท้อนผลลัพธ์ที่เร็วขึ้น

บน avarage: unserialize ชนะ 96 ครั้งมากกว่า 4 ครั้ง json_decode ด้วยความละโมบ 1.5ms มากกว่า 2.5ms


3

ก่อนที่คุณจะตัดสินใจขั้นสุดท้ายโปรดทราบว่ารูปแบบ JSON ไม่ปลอดภัยสำหรับอาร์เรย์ที่เชื่อมโยง - json_decode()จะส่งคืนเป็นวัตถุแทน:

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

ผลลัพธ์คือ:

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

แน่นอนว่าคุณพูดถูก ฉันหมายความว่ามันเป็นสัญกรณ์วัตถุจาวาสคริปต์หลังจากนั้น ! โชคดีที่ถ้าคุณรู้ว่าสิ่งที่คุณเข้ารหัสjson_encodeนั้นเป็นอาเรย์แบบเชื่อมโยงคุณสามารถบังคับให้มันกลับมาเป็นอาเรย์ได้เช่นกัน: $json = json_encode($some_assoc_array); $back_to_array = (array)json_decode($json);นอกจากนี้ยังเป็นเรื่องดีที่จะต้องทราบว่าคุณสามารถเข้าถึงออบเจ็กต์ได้เช่นเดียวกับอาร์เรย์ใน PHP ไม่มีใครรู้ถึงความแตกต่าง แม้ว่าจุดดี!
KyleFarris

30
@toomuchphp ขออภัย แต่คุณคิดผิด มีพารามิเตอร์ตัวที่สองสำหรับ json_decode 'bool $ assoc = false' ที่ทำให้ json_decode สร้างอาร์เรย์ @KyleFarris นี่ควรจะเร็วกว่าการใช้ typecast ในอาเรย์
janpio

คำตอบไม่ถูกต้อง เมื่อใช้จริงเป็นพารามิเตอร์ที่สองของฟังก์ชั่น json_decode () จะกลับอาร์เรย์เชื่อมโยงแทนวัตถุ
Marvin Saldinger

3

ก่อนอื่นฉันเปลี่ยนสคริปต์เพื่อทำการเปรียบเทียบเพิ่มเติม (และยังดำเนินการ 1,000 ครั้งแทนที่จะเป็นเพียง 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';
}

ฉันใช้โครงสร้างของ PHP 7 นี้:

PHP 7.0.14 (cli) (สร้าง: 18 ม.ค. 2017 19:13:23) (NTS) ลิขสิทธิ์ (c) 1997-2016 กลุ่ม PHP Zend Engine v3.0.0, ลิขสิทธิ์ (c) 1998-2016 Zend Technologies พร้อม Zend OPcache v7.0.14, ลิขสิทธิ์ (c) 1999-2016 โดย Zend Technologies

และผลลัพธ์ของฉันคือ:

ทำให้เป็นอันดับ () (ชนะ: 999) เร็วกว่า json_encode ประมาณ 10.98% () unserialize () (ชนะ: 987) ประมาณ 33.26% เร็วกว่า json_decode (): unserialize () (ชนะ: 987) ประมาณ 48.35% ()

ดังนั้นอย่างชัดเจน , อันดับ / unserialize เป็นเร็วที่สุดวิธีการในขณะที่ json_encode / ถอดรหัสเป็นแบบพกพามากที่สุด

หากคุณพิจารณาสถานการณ์ที่คุณอ่าน / เขียนข้อมูลแบบอนุกรม 10 เท่าหรือบ่อยกว่าที่คุณต้องการส่งไปหรือรับจากระบบที่ไม่ใช่ PHP คุณยังคงดีกว่าที่จะใช้ serialize / unserialize และมี json_encode หรือ json_decode ก่อนการทำให้เป็นอนุกรม ในแง่ของเวลา


2

ตรวจสอบผลลัพธ์ที่นี่ (ขออภัยที่แฮ็ควางโค้ด PHP ลงในกล่องรหัส JS):

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

ผลลัพธ์: serialize()และunserialize()ทั้งคู่เร็วขึ้นอย่างมากใน PHP 5.4 ในอาร์เรย์ที่มีขนาดแตกต่างกัน

ฉันสร้างสคริปต์ทดสอบสำหรับข้อมูลจริงเพื่อเปรียบเทียบ json_encode กับ serialize และ json_decode กับ unserialize การทดสอบรันบนระบบแคชของไซต์อีคอมเมิร์ซที่กำลังการผลิต มันใช้ข้อมูลที่มีอยู่แล้วในแคชและทดสอบเวลาในการเข้ารหัส / ถอดรหัส (หรือทำให้เป็นอนุกรม / unserialize) ข้อมูลทั้งหมดและฉันวางไว้ในตารางที่มองเห็นง่าย

ฉันทำสิ่งนี้บนเซิร์ฟเวอร์โฮสติ้งที่ใช้ร่วมกันของ PHP 5.4

ผลการวิจัยสรุปได้อย่างชัดเจนว่าสำหรับชุดข้อมูลขนาดใหญ่ถึงขนาดเล็กเหล่านี้เป็นลำดับและไม่ระบุเป็นผู้ชนะที่ชัดเจน โดยเฉพาะอย่างยิ่งสำหรับกรณีการใช้งานของฉัน json_decode และ unserialize เป็นสิ่งที่สำคัญที่สุดสำหรับระบบแคช Unserialize เกือบจะเป็นผู้ชนะที่แพร่หลายทุกคนที่นี่ โดยทั่วไปแล้ว 2 ถึง 4 ครั้ง (บางครั้ง 6 หรือ 7 ครั้ง) เร็วเท่า json_decode

เป็นที่น่าสนใจที่จะสังเกตเห็นความแตกต่างในผลลัพธ์จาก @ peter-bailey

นี่คือโค้ด PHP ที่ใช้ในการสร้างผลลัพธ์:

<?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

เพียงแค่ fyi - ถ้าคุณต้องการซีเรียลไลซ์ข้อมูลของคุณเป็นสิ่งที่ง่ายต่อการอ่านและเข้าใจเช่นเดียวกับ JSON แต่ด้วยการบีบอัดที่มากขึ้นและประสิทธิภาพที่สูงขึ้นคุณควรตรวจสอบmessagepack


2
หากเป็นเพียง fyi คุณควรแสดงความคิดเห็น
technophyle

0

JSON ดีกว่าถ้าคุณต้องการสำรองข้อมูลและกู้คืนในเครื่องอื่นหรือผ่านทาง FTP

ตัวอย่างเช่นการทำให้เป็นอนุกรมถ้าคุณเก็บข้อมูลบนเซิร์ฟเวอร์ Windows ให้ดาวน์โหลดผ่าน FTP และกู้คืนบน Linux ซึ่งไม่สามารถทำงานได้อีกต่อไปเนื่องจากการเข้ารหัส charachter อีกครั้งเนื่องจากอนุกรมจัดเก็บความยาวของสตริงและใน Unicode > การแปลงรหัส UTF-8 บาง charachter 1 ไบต์อาจกลายเป็น 2 ไบต์ยาวทำให้อัลกอริทึมผิดพลาด


0

ขอบคุณ - สำหรับรหัสมาตรฐานนี้:

ผลลัพธ์ของฉันในอาร์เรย์ที่ฉันใช้สำหรับการกำหนดค่านั้นเหมือนกัน: JSON เข้ารหัสใน 0.0031511783599854 วินาที
PHP ต่อเนื่องใน 0.0037961006164551 วินาที
json_encode()นั้นประมาณ 20.47% เร็วกว่าserialize() JSON ที่เข้ารหัสใน 0.0070841312408447 วินาที
PHP ต่อเนื่องใน 0.0035839080810547 วินาที
unserialize()ถูกประมาณ 97.66% เร็วกว่าjson_encode()

ดังนั้น - ทดสอบกับข้อมูลของคุณเอง


คุณหมายถึง json_decode () ใน "unserialize () ประมาณ 97.66% เร็วกว่า json_encode ()" ใช่ไหม
Meezaan-ud-Din

0

หากจะสรุปสิ่งที่ผู้คนพูดที่นี่ json_decode / encode ดูเหมือนจะเร็วกว่า serialize / unserialize แต่ถ้าคุณทำ var_dump ประเภทของวัตถุที่เป็นอนุกรมจะเปลี่ยนไป ถ้าด้วยเหตุผลบางอย่างที่คุณต้องการรักษาประเภทให้ไปกับอนุกรม!

(ลองตัวอย่างเช่น stdClass vs array)

อันดับ / 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 เข้ารหัส / ถอดรหัส

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]

ในขณะที่คุณเห็น json_encode / decode แปลงทั้งหมดเป็น stdClass ซึ่งไม่ดีข้อมูลวัตถุที่หายไป ... ดังนั้นตัดสินใจตามความต้องการโดยเฉพาะอย่างยิ่งถ้าไม่ใช่อาร์เรย์เท่านั้น ...


เพียงทราบ: คำตอบอื่น ๆ ส่วนใหญ่บอกว่าเป็นอันดับ / unserialize เร็วขึ้น
Ecker00

-3

ผมขอแนะนำให้คุณใช้ซูเปอร์แคชซึ่งเป็นกลไกแคชไฟล์ซึ่งจะไม่ใช้หรือjson_encode serializeมันใช้งานง่ายและรวดเร็วมากเมื่อเทียบกับกลไกแคช PHP อื่น ๆ

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

Ex:

<?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 แม้ว่ามันอาจจะเป็นทางออกที่ดีกว่า แต่ก็ไม่มีส่วนใดของคำตอบนี้ตอบคำถามของ OP ได้จริง ในอนาคตอาจลองตอบคำถาม แต่ทิ้งข้อเสนอแนะไว้ที่ด้านล่างว่าทางออกอื่นอาจคุ้มค่ากับการตรวจสอบ
starbeamrainbowlabs
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.