Membandingkan Performa: Loops vs. Iterators
Buat menentukan apakah kita sebaiknya memakai loops atau iterators, kita
perlu tahu implementasi mana yang lebih cepat: versi fungsi search yang
memakai for loop eksplisit atau versi yang memakai iterators.
Kita menjalankan sebuah benchmark (pengujian performa) dengan memuat seluruh isi
buku The Adventures of Sherlock Holmes karya Sir Arthur Conan Doyle ke dalam
sebuah String dan mencari kata the di dalam isinya. Berikut adalah hasil dari
benchmark pada fungsi search versi for loop dan versi iterators:
test bench_search_for ... bench: 19,620,300 ns/iter (+/- 915,700)
test bench_search_iter ... bench: 19,234,900 ns/iter (+/- 657,200)
Kedua implementasi ini punya performa yang mirip! Kita tidak bakal menjelaskan kode benchmark-nya di sini karena tujuannya bukanlah buat membuktikan kalau kedua versi itu persis ekuivalen, tapi buat ngasih gambaran umum soal gimana perbandingan performa kedua implementasi ini.
Untuk benchmark yang lebih komprehensif, kita sebaiknya menguji dengan memakai
berbagai teks dari berbagai ukuran sebagai contents, kata yang berbeda-beda dan
kata dengan panjang yang beda-beda sebagai query, dan berbagai jenis variasi
lainnya. Poin utamanya adalah ini: iterators, meskipun merupakan sebuah
abstraksi tingkat tinggi (high-level abstraction), bakal di-compile menjadi kode
yang kurang lebih sama seperti kalau kita menulis sendiri kode tingkat rendah
(lower-level code)-nya secara manual. Iterators adalah salah satu dari
zero-cost abstractions (abstraksi tanpa biaya) di Rust, yang maksudnya adalah
penggunaan abstraksi tersebut tidak menambahkan beban (overhead) apa pun pas
runtime. Ini analog dengan gimana Bjarne Stroustrup, perancang dan
pengimplementasi asli dari C++, mendefinisikan zero-overhead di
“Foundations of C++” (2012):
Secara umum, implementasi C++ mematuhi prinsip zero-overhead: Apa yang tidak kita pakai, kita tidak perlu membayarnya. Dan lebih jauh lagi: Apa yang kita pakai, kita tidak bakal bisa nulis kodenya secara manual dengan lebih baik lagi.
Di banyak kasus, kode Rust yang memakai iterators di-compile menjadi kode assembly (bahasa rakitan) yang sama persis kayak yang bakal kita tulis pakai tangan sendiri. Berbagai optimasi kayak loop unrolling dan menghilangkan pengecekan batas (bounds checking) pada akses array bakal diterapkan dan membikin kode akhirnya jadi sangat efisien. Sekarang karena kita sudah tahu hal ini, kita bisa memakai iterators dan closures tanpa rasa takut! Mereka bikin kode kelihatan seperti di tingkat yang lebih tinggi (higher level) tapi tidak mengenakan hukuman performa (performance penalty) pas runtime karena ngelakuin hal tersebut.
Ringkasan
Closures dan iterators adalah fitur-fitur Rust yang terinspirasi dari ide-ide bahasa pemrograman fungsional. Mereka berkontribusi pada kemampuan Rust buat mengekspresikan ide-ide tingkat tinggi (high-level ideas) dengan jelas sembari mempertahankan performa tingkat rendah (low-level performance). Implementasi dari closures dan iterators dirancang sedemikian rupa sehingga performa pas runtime tidak terpengaruh. Ini adalah bagian dari tujuan Rust buat berjuang menyediakan zero-cost abstractions.
Sekarang setelah kita meningkatkan kemampuan ekspresi dari project I/O kita,
mari kita lihat beberapa fitur cargo lainnya yang bakal membantu kita membagikan
project kita dengan dunia.