Performa yang terkait dengan Array dan Objek dalam JavaScript (khususnya Google V8) akan sangat menarik untuk didokumentasikan. Saya tidak menemukan artikel komprehensif tentang topik ini di mana pun di Internet.
Saya memahami bahwa beberapa Objek menggunakan kelas sebagai struktur data yang mendasarinya. Jika ada banyak properti, terkadang diperlakukan sebagai tabel hash?
Saya juga memahami bahwa Array terkadang diperlakukan seperti C ++ Array (yaitu pengindeksan acak cepat, penghapusan lambat, dan pengubahan ukuran). Dan, di lain waktu, mereka diperlakukan lebih seperti Objek (pengindeksan cepat, penyisipan / penghapusan cepat, lebih banyak memori). Dan, mungkin terkadang mereka disimpan sebagai daftar tertaut (yaitu pengindeksan acak yang lambat, penghapusan / penyisipan cepat di awal / akhir)
Apa kinerja yang tepat dari pengambilan dan manipulasi Array / Objek dalam JavaScript? (khusus untuk Google V8)
Lebih khusus lagi, apa dampak kinerja:
- Menambahkan properti ke Objek
- Menghapus properti dari Objek
- Mengindeks properti di Objek
- Menambahkan item ke Array
- Menghapus item dari Array
- Mengindeks item dalam Array
- Memanggil Array.pop ()
- Memanggil Array.push ()
- Memanggil Array.shift ()
- Memanggil Array.unshift ()
- Memanggil Array.slice ()
Artikel atau tautan apa pun untuk detail lebih lanjut akan dihargai juga. :)
EDIT: Saya benar-benar bertanya-tanya bagaimana array dan objek JavaScript bekerja di bawah tenda. Juga, dalam konteks apa mesin V8 "tahu" untuk "beralih" ke struktur data lain?
Misalnya, saya membuat array dengan ...
var arr = [];
arr[10000000] = 20;
arr.push(21);
Apa yang sebenarnya terjadi disini?
Atau ... bagaimana dengan ini ... ???
var arr = [];
//Add lots of items
for(var i = 0; i < 1000000; i++)
arr[i] = Math.random();
//Now I use it like a queue...
for(var i = 0; i < arr.length; i++)
{
var item = arr[i].shift();
//Do something with item...
}
Untuk array konvensional, kinerjanya akan sangat buruk; sedangkan, jika LinkedList digunakan ... tidak terlalu buruk.
sumber
Jawaban:
Saya membuat rangkaian pengujian, tepatnya untuk menjelajahi masalah ini (dan lebih banyak lagi) ( salinan yang diarsipkan ).
Dan dalam hal itu, Anda dapat melihat masalah kinerja dalam 50+ test case tester ini (ini akan memakan waktu lama).
Juga seperti yang disarankan oleh namanya, ini mengeksplorasi penggunaan menggunakan sifat daftar tertaut asli dari struktur DOM.
(Saat ini turun, sedang dibangun kembali) Lebih detail di blog saya tentang ini .
Ringkasannya adalah sebagai berikut
Array.shift()
adalah cepat ~ kira-kira 6x lebih lambat dari pop array, tetapi ~ kira-kira 100x lebih cepat daripada penghapusan atribut objek.Array.push( data );
lebih cepat dariArray[nextIndex] = data
hampir 20 (array dinamis) hingga 10 (array tetap) kali lipat.Array.unshift(data)
lebih lambat seperti yang diharapkan, dan ~ kira-kira 5x lebih lambat dari penambahan properti baru.array[index] = null
Menghapus nilai lebih cepat daripada menghapusnyadelete array[index]
(tidak ditentukan) dalam array dengan ~ kira-kira 4x ++ lebih cepat.obj[attr] = null
~ kira-kira 2x lebih lambat daripada hanya menghapus atributdelete obj[attr]
Array.splice(index,0,data)
lambat, sangat lambat.Array.splice(index,1,data)
telah dioptimalkan (tidak ada perubahan panjang) dan 100x lebih cepat dari sekedar sambunganArray.splice(index,0,data)
dll.splice(index,1)
penghapusan (Jika merusak sistem pengujian).Catatan: Metrik ini hanya berlaku untuk larik / objek besar yang v8 tidak "sepenuhnya dioptimalkan". Ada kasus kinerja yang dioptimalkan sangat terisolasi untuk larik / ukuran objek kurang dari ukuran sewenang-wenang (24?). Detail selengkapnya dapat dilihat secara luas di beberapa video Google IO.
Catatan 2: Hasil kinerja luar biasa ini tidak dibagikan di seluruh browser, terutama
*cough*
IE. Tesnya juga sangat besar, oleh karena itu saya belum sepenuhnya menganalisis dan mengevaluasi hasilnya: silakan edit di =)Catatan yang Diperbarui (des 2012): Perwakilan Google memiliki video di youtubes yang menjelaskan cara kerja chrome itu sendiri (seperti saat beralih dari larik daftar tertaut ke larik tetap, dll), dan cara mengoptimalkannya. Lihat GDC 2012: Dari Konsol ke Chrome untuk selengkapnya.
sumber
Pada tingkat dasar yang tetap dalam ranah JavaScript, properti pada objek adalah entitas yang jauh lebih kompleks. Anda dapat membuat properti dengan setter / getter, dengan enumerabilitas, kemampuan menulis, dan konfigurasi yang berbeda. Item dalam larik tidak dapat dikustomisasi dengan cara ini: item itu ada atau tidak. Pada tingkat mesin yang mendasarinya, hal ini memungkinkan pengoptimalan yang lebih banyak dalam hal mengatur memori yang mewakili struktur.
Dalam hal mengidentifikasi array dari sebuah objek (kamus), mesin JS selalu membuat garis eksplisit di antara keduanya. Itulah mengapa ada banyak artikel tentang metode mencoba membuat objek semi-palsu mirip Array yang berperilaku seperti satu tetapi memungkinkan fungsionalitas lain. Alasan pemisahan ini bahkan ada adalah karena mesin JS sendiri menyimpan keduanya secara berbeda.
Properti dapat disimpan pada objek array, tetapi ini hanya menunjukkan bagaimana JavaScript bersikeras membuat semuanya menjadi objek. Nilai yang diindeks dalam larik disimpan secara berbeda dari properti apa pun yang Anda putuskan untuk disetel pada objek larik yang mewakili data larik yang mendasarinya.
Setiap kali Anda menggunakan objek array yang sah dan menggunakan salah satu metode standar untuk memanipulasi array itu, Anda akan mencapai data array yang mendasarinya. Khususnya di V8, ini pada dasarnya sama dengan array C ++ sehingga aturan tersebut akan berlaku. Jika karena alasan tertentu Anda bekerja dengan array yang mesin tidak dapat menentukan dengan percaya diri adalah array, maka Anda berada di tempat yang jauh lebih goyah. Dengan versi terbaru V8, ada lebih banyak ruang untuk bekerja. Misalnya, dimungkinkan untuk membuat kelas yang memiliki Array.prototype sebagai prototipe dan masih mendapatkan akses efisien ke berbagai metode manipulasi larik asli. Tapi ini adalah perubahan terkini.
Tautan khusus ke perubahan terkini untuk manipulasi larik mungkin berguna di sini:
Sebagai tambahan, inilah Array Pop dan Array Push langsung dari sumber V8, keduanya diterapkan di JS itu sendiri:
sumber
Saya ingin melengkapi jawaban yang ada dengan penyelidikan atas pertanyaan tentang bagaimana implementasi berperilaku terkait dengan larik yang berkembang: Jika menerapkannya dengan cara "biasa", orang akan melihat banyak dorongan cepat dengan dorongan lambat yang jarang dan diselingi pada titik mana salinan implementasi representasi internal array dari satu buffer ke buffer yang lebih besar.
Anda dapat melihat efek ini dengan sangat baik, ini dari Chrome:
Meskipun setiap push diprofilkan, outputnya hanya berisi push yang membutuhkan waktu di atas ambang tertentu. Untuk setiap pengujian saya menyesuaikan ambang untuk mengecualikan semua dorongan yang tampaknya mewakili dorongan cepat.
Jadi angka pertama mewakili elemen mana yang telah dimasukkan (baris pertama untuk elemen ke-17), angka kedua adalah berapa lama waktu yang dibutuhkan (untuk banyak array, benchmark dilakukan secara paralel), dan nilai terakhir adalah pembagian dari nomor pertama dengan yang ada di baris sebelumnya.
Semua baris yang memiliki waktu eksekusi kurang dari 2 md dikecualikan untuk Chrome.
Anda dapat melihat bahwa Chrome meningkatkan ukuran array dalam kekuatan 1.5, ditambah beberapa offset untuk memperhitungkan array kecil.
Untuk Firefox, ini adalah kekuatan dua:
Saya harus menaikkan ambang cukup sedikit di Firefox, itulah mengapa kami mulai dari # 126.
Dengan IE, kami mendapatkan campuran:
Ini adalah kekuatan dua pada awalnya dan kemudian berpindah ke kekuatan lima pertiga.
Jadi semua implementasi umum menggunakan cara "normal" untuk array (alih-alih menjadi gila dengan tali , misalnya).
Ini kode patokan dan biolanya .
sumber
Saat berjalan di bawah node.js 0.10 (dibangun di atas v8) saya melihat penggunaan CPU yang tampak berlebihan untuk beban kerja. Saya menelusuri satu masalah kinerja ke fungsi yang memeriksa keberadaan string dalam array. Jadi saya menjalankan beberapa tes.
Memuat 91k entri ke dalam larik (dengan validasi & push) lebih cepat daripada menyetel obj [key] = nilai.
Pada tes berikutnya, saya mencari setiap nama host dalam daftar satu kali (iterasi 91k, untuk rata-rata waktu pencarian):
Aplikasi di sini adalah Haraka (server SMTP) dan memuat host_list sekali saat startup (dan setelah perubahan) dan kemudian melakukan pencarian ini jutaan kali selama operasi. Beralih ke suatu objek adalah kemenangan kinerja yang besar.
sumber