Sejak kelas pemrograman pertama saya di sekolah menengah, saya telah mendengar bahwa operasi string lebih lambat - yaitu lebih mahal - daripada mitos "operasi rata-rata." Mengapa membuatnya begitu lambat? (Pertanyaan ini sengaja dibiarkan melebar.)
Sejak kelas pemrograman pertama saya di sekolah menengah, saya telah mendengar bahwa operasi string lebih lambat - yaitu lebih mahal - daripada mitos "operasi rata-rata." Mengapa membuatnya begitu lambat? (Pertanyaan ini sengaja dibiarkan melebar.)
Jawaban:
"Operasi rata-rata" berlangsung pada primitif. Tetapi bahkan dalam bahasa di mana string diperlakukan sebagai primitif, mereka masih array di bawah tenda, dan melakukan apa pun yang melibatkan seluruh string membutuhkan waktu O (N), di mana N adalah panjang string.
Misalnya, menambahkan dua angka biasanya membutuhkan 2-4 instruksi ASM. Menggabungkan ("menambahkan") dua string memerlukan alokasi memori baru dan satu atau dua salinan string, yang melibatkan seluruh string.
Faktor-faktor bahasa tertentu dapat memperburuknya. Dalam C, misalnya, string hanyalah sebuah penunjuk ke array karakter yang diakhiri null. Ini berarti bahwa Anda tidak tahu berapa lama, jadi tidak ada cara untuk mengoptimalkan loop penyalinan string dengan operasi gerakan cepat; Anda perlu menyalin satu karakter pada satu waktu sehingga Anda dapat menguji setiap byte untuk terminator nol.
char*
, bukan strbuf
, dan Anda kembali ke titik 1. Hanya ada begitu banyak Anda dapat dilakukan ketika desain yang buruk dimasukkan ke dalam bahasa.
buf
petunjuknya ada di sana. Saya tidak pernah bermaksud mengatakan bahwa itu tidak tersedia; sebaliknya, itu perlu. Kode apa pun yang tidak tahu tentang tipe string Anda yang dioptimalkan-tetapi-tidak-standar, termasuk hal-hal mendasar seperti pustaka standar , masih harus kembali pada lambat, tidak aman char*
. Anda dapat memanggil FUD itu jika Anda mau, tetapi itu tidak membuatnya tidak benar.
Ini adalah utas lama dan saya pikir jawaban lainnya bagus, tetapi mengabaikan sesuatu, jadi inilah (sen) 2 sen saya.
Masalah dengan string adalah bahwa mereka adalah warga negara kelas dua di sebagian besar bahasa, dan pada kenyataannya sebagian besar waktu sebenarnya bukan bagian dari spesifikasi bahasa itu sendiri: mereka adalah konstruksi yang diimplementasikan oleh perpustakaan dengan beberapa lapisan gula sintaksis sesekali di bagian atas untuk membuat mereka kurang dari rasa sakit untuk digunakan.
Konsekuensi langsung dari ini adalah bahwa bahasa menyembunyikan bagian yang sangat besar dari kerumitannya jauh dari pandangan Anda, dan Anda membayar untuk efek samping licik karena Anda tumbuh menjadi kebiasaan menganggap mereka seperti entitas atom tingkat rendah, seperti tipe primitif lainnya (seperti yang dijelaskan oleh jawaban terpilih dan lainnya).
Salah satu elemen dari "kompleksitas" yang mendasarinya adalah sebagian besar implementasi string akan menggunakan struktur data sederhana dengan beberapa ruang memori yang berdekatan untuk merepresentasikan string: array yang baik dari Anda.
Ini masuk akal, ingatlah, karena Anda ingin akses ke string secara keseluruhan menjadi cepat. Tapi itu menyiratkan kemungkinan biaya yang mengerikan ketika Anda ingin memanipulasi string ini. Mengakses elemen di tengah mungkin cepat jika Anda tahu indeks apa yang Anda cari, tetapi mencari elemen berdasarkan suatu kondisi tidak.
Bahkan mengembalikan ukuran string mungkin mahal, jika bahasa Anda tidak men-cache panjang string dan perlu dijalankan untuk menghitung karakter.
Untuk alasan yang sama, menambahkan elemen ke string Anda akan terbukti mahal karena kemungkinan besar Anda perlu mengalokasikan kembali sejumlah memori agar operasi ini dapat terjadi.
Jadi, bahasa yang berbeda mengambil pendekatan yang berbeda untuk masalah ini. Java, misalnya, mengambil kebebasan membuat string tidak berubah untuk beberapa alasan yang valid (panjang caching, keamanan thread) dan untuk rekan-rekan yang bisa berubah (StringBuffer dan StringBuilder) akan memilih untuk mengalokasikan ukuran menggunakan potongan berukuran lebih besar untuk tidak perlu mengalokasikan setiap saat, tetapi lebih berharap untuk skenario kasus terbaik. Ini umumnya bekerja dengan baik, tetapi sisi buruknya adalah terkadang membayar dampak memori.
Juga, dan sekali lagi ini disebabkan oleh fakta bahwa lapisan gula sintaksis bahasa Anda menyembunyikan ini dari Anda untuk bermain bagus, Anda sering tidak menganggapnya sebagai dukungan unicode (terutama selama Anda tidak benar-benar membutuhkannya) dan menabrak dinding itu). Dan beberapa bahasa, sebagai pemikiran ke depan, tidak menerapkan string dengan array mendasar dari primitif char 8-bit sederhana. Mereka dipanggang dalam dukungan UTF-8 atau UTF-16 atau apa pun yang Anda miliki untuk Anda, dan konsekuensinya adalah konsumsi memori yang jauh lebih besar, yang sering kali tidak diperlukan, dan waktu pemrosesan yang lebih besar untuk mengalokasikan memori, memproses string, dan mengimplementasikan semua logika yang sejalan dengan memanipulasi poin kode.
Hasil dari semua ini, adalah ketika Anda melakukan sesuatu yang setara dalam pseudo-code ke:
hello = "hello,"
world = " world!"
str = hello + world
Mungkin tidak - terlepas dari semua upaya terbaik yang dilakukan pengembang bahasa untuk membuat mereka berperilaku seperti yang Anda inginkan - sesederhana:
a = 1;
b = 2;
shouldBeThree = a + b
Sebagai tindak lanjut, Anda mungkin ingin membaca:
Ungkapan "operasi rata-rata" mungkin singkatan untuk operasi tunggal dari mesin Program Acak-Tersimpan Program teoritis . Ini adalah mesin teoretis yang biasa digunakan untuk menganalisis waktu berjalan berbagai algoritma.
Operasi generik biasanya diambil untuk memuat, menambah, mengurangi, menyimpan, cabang. Mungkin juga membaca, mencetak, dan berhenti.
Tetapi sebagian besar operasi string memerlukan beberapa operasi mendasar ini. Misalnya, menduplikasi string biasanya membutuhkan operasi penyalinan, dan karenanya sejumlah operasi yang sebanding dengan panjang string (yaitu, "linier"). Menemukan substring di dalam string lain juga memiliki kompleksitas linier.
Ini sepenuhnya tergantung pada operasi, bagaimana string diwakili, dan optimasi apa yang ada. Jika panjang string 4 atau 8 byte (dan disejajarkan), mereka tidak akan selalu lebih lambat - banyak operasi akan sama cepatnya dengan primitif. Atau, jika semua string memiliki hash 32-bit atau 64-bit, banyak operasi juga akan sama cepat (meskipun Anda membayar biaya hashing di depan).
Ini juga tergantung pada apa yang Anda maksud dengan "lambat". Sebagian besar program akan memproses string dengan cepat untuk apa yang dibutuhkan. Perbandingan string mungkin tidak secepat membandingkan dua int, tetapi hanya profil yang akan mengungkapkan apa artinya "lambat" untuk program Anda.
Biarkan saya menjawab pertanyaan Anda dengan pertanyaan. Mengapa mengucapkan serangkaian kata lebih lama daripada mengucapkan satu kata?