2 poin oleh GN⁺ 2024-11-30 | 1 komentar | Bagikan ke WhatsApp

Benchmark

  • Apa itu coroutine?

    • Coroutine adalah komponen program komputer yang dapat menangguhkan dan melanjutkan eksekusi program, yaitu generalisasi dari subrutin untuk multitasking kooperatif.
    • Cocok untuk mengimplementasikan komponen program seperti pekerjaan kooperatif, pengecualian, event loop, iterator, daftar tak terbatas, dan pipe.
  • Rust

    • Ditulis dua program: program yang menggunakan tokio dan async_std.
    • Keduanya adalah runtime asinkron yang umum digunakan di Rust.
  • C#

    • C# mendukung async/await, mirip dengan Rust.
    • Sejak .NET 7, tersedia kompilasi NativeAOT sehingga kode terkelola dapat dijalankan tanpa VM.
  • NodeJS

    • Menggunakan Promise.all untuk tugas asinkron.
  • Python

    • Menggunakan modul asyncio untuk menjalankan tugas asinkron.
  • Go

    • Mengimplementasikan konkurensi menggunakan goroutine, dan menunggu tugas dengan WaitGroup.
  • Java

    • Sejak JDK 21, tersedia virtual thread, yang merupakan konsep serupa dengan goroutine.
    • Dapat membuat native image menggunakan GraalVM.

Lingkungan pengujian

  • Perangkat keras: Intel(R) Core(TM) i7-13700K generasi ke-13
  • Sistem operasi: Debian GNU/Linux 12 (bookworm)
  • Rust: 1.82.0
  • .NET: 9.0.100
  • Go: 1.23.3
  • Java: openjdk 23.0.1
  • Java (GraalVM): java 23.0.1
  • NodeJS: v23.2.0
  • Python: 3.13.0

Hasil

  • Penggunaan memori minimum

    • Rust, C# (NativeAOT), dan Go dikompilasi menjadi biner native sehingga menggunakan memori yang kecil.
    • Java (native image GraalVM) juga menunjukkan performa yang baik, tetapi tetap menggunakan lebih banyak memori dibanding bahasa lain yang dikompilasi secara statis.
  • 10 ribu tugas

    • Penggunaan memori Rust hampir tidak meningkat.
    • C# (NativeAOT) juga menggunakan sedikit memori.
    • Go menggunakan lebih banyak memori dari yang diperkirakan.
  • 100 ribu tugas

    • Rust dan C# menunjukkan performa yang baik.
    • C# (NativeAOT) menggunakan lebih sedikit memori dibanding Rust.
  • 1 juta tugas

    • C# mengungguli semua bahasa lain dan menggunakan memori paling sedikit.
    • Rust juga sangat efisien dalam penggunaan memori.
    • Go menggunakan memori lebih banyak dibanding bahasa lain.

Kesimpulan

  • Banyak tugas konkuren dapat mengonsumsi memori dalam jumlah besar meskipun tidak menjalankan pekerjaan yang kompleks.
  • Peningkatan pada .NET dan NativeAOT sangat menonjol, dan native image Java yang dibangun dengan GraalVM juga sangat efisien dalam penggunaan memori.
  • Goroutine masih tidak efisien dari sisi konsumsi sumber daya.

Lampiran

  • Di Rust (tokio), penggunaan memori dikurangi setengah dengan memakai loop for alih-alih join_all. Rust menjadi pemimpin mutlak dalam benchmark ini.

1 komentar

 
GN⁺ 2024-11-30
Opini Hacker News
  • Benchmark tersebut tidak secara tepat mencerminkan perbedaan cara Node dan Go menangani pemrosesan asinkron. Node menggunakan Promise.all sedangkan Go menggunakan goroutine, sehingga ada perbedaan. Akan menarik untuk membandingkan perbedaan penggunaan memori antara I/O asinkron dan tugas yang CPU-bound

  • Menjelaskan perbedaan antara "tugas yang menunggu selama 10 detik" dan "tugas yang dibangunkan setelah 10 detik". Penggunaan memori pada kode Go jauh berbeda dibandingkan kode lainnya

  • Mengusulkan metode yang menggunakan goroutine untuk menjadwalkan timer dan goroutine lain untuk menangani sinyal timer agar perbandingan antara Go dan Node lebih adil. Juga disebutkan bahwa aneh Bun dan Deno tidak disertakan dalam Node

  • Banyak tugas serentak memang dapat menghabiskan banyak memori, tetapi jika data per tugas lebih dari beberapa KB, overhead memori scheduler menjadi cukup kecil untuk diabaikan

  • Penggunaan memori bisa berbeda tergantung definisi dari "tugas serentak". Dalam implementasi yang efisien, sekitar 200MB dibutuhkan untuk 1M tugas serentak

  • Menunjukkan bahwa Go tertinggal lebih dari 2x dibanding Java dalam penggunaan memori, dan menyebut benchmark tersebut tidak mewakili program nyata

  • Membandingkan bahasa dengan kode sederhana bisa tidak adil bagi pengembang, dan disarankan menambahkan pekerjaan nyata untuk mengukur penggunaan memori serta perbedaan penjadwalan

  • Mengatakan bahwa benchmark sering kali penuh kesalahan, dan ia tidak memahami motivasi orang-orang yang memublikasikan benchmark semacam ini

  • Benchmark Java kemungkinan salah, karena ukuran awal ArrayList tidak ditentukan sehingga banyak objek tidak perlu dibuat

  • Menjelaskan mengapa kode async Rust selesai lebih cepat dari perkiraan. Itu karena tokio::time::sleep() melacak titik waktu saat future dibuat