2 poin oleh GN⁺ 2025-10-28 | 1 komentar | Bagikan ke WhatsApp
  • Penulis mencoba pendekatan baru saat mempelajari bahasa Zig sambil mengerjakan proyek penulisan ulang indeks AcoustID, dipicu oleh keterbatasan dalam pemrograman jaringan
  • Untuk menghadirkan model I/O asinkron dan konkurensi yang sebelumnya digunakan di C++ dan Go ke Zig, ia memutuskan mengembangkan pustakanya sendiri
  • Hasilnya, ia membuat pustaka Zio yang mengimplementasikan model konkurensi bergaya Go agar sesuai dengan Zig, sehingga memungkinkan penulisan kode asinkron yang terlihat seperti sinkron tanpa callback
  • Zio mendukung I/O jaringan dan berkas asinkron, channel, primitive sinkronisasi, pemantauan sinyal dan lainnya, serta menunjukkan performa lebih cepat daripada Go atau Tokio milik Rust dalam mode single-thread
  • Proyek ini menunjukkan kemungkinan menggabungkan performa tingkat sistem Zig dengan model konkurensi modern, dan dinilai sebagai titik balik penting dalam perluasan ekosistem Zig

Bahasa Zig dan motivasi awal

  • Penulis sebelumnya telah mengamati Zig, yang awalnya dirancang sebagai bahasa tingkat rendah untuk perangkat lunak audio, tetapi belum merasa ada kebutuhan praktis untuk menggunakannya
    • Ia mulai tertarik setelah melihat Andrew Kelley, pencipta Zig, mengimplementasikan ulang algoritme Chromaprint milik penulis dalam Zig
  • Ia menjadikan proyek penulisan ulang inverted index di AcoustID sebagai kesempatan untuk belajar Zig, dan pada akhirnya berhasil mencapai implementasi yang lebih cepat dan lebih skalabel dibanding versi C++
  • Namun, pada tahap penambahan antarmuka server, ia menghadapi masalah kurangnya dukungan jaringan asinkron

Pendekatan sebelumnya dan keterbatasannya

  • Pada versi C++ sebelumnya, framework Qt digunakan untuk menangani I/O asinkron; walaupun berbasis callback, pendekatan ini tetap dapat dipakai berkat dukungannya yang kaya
  • Dalam prototipe berikutnya, ia memanfaatkan kemudahan jaringan dan konkurensi dari bahasa Go, tetapi Zig tidak memiliki abstraksi pada tingkat yang setara
  • Untuk mengimplementasikan server TCP dan lapisan klaster di Zig, muncul inefisiensi karena harus membuat banyak thread
    • Untuk mengatasinya, ia menulis sendiri klien Zig untuk sistem pesan NATS (nats.zig) sambil mendalami fitur jaringan di Zig
Iklan

Munculnya pustaka Zio

  • Berdasarkan pengalaman tersebut, ia merilis Zio: pustaka I/O asinkron dan konkurensi untuk Zig
  • Zio bertujuan memungkinkan penulisan kode asinkron tanpa callback, dengan struktur yang secara internal bekerja secara asinkron tetapi dari luar terlihat seperti sinkron
  • Zio mengimplementasikan model konkurensi bergaya Go secara terbatas agar sesuai dengan Zig
    • Task di Zio berbentuk stackful coroutine dengan stack berukuran tetap
    • Saat stream.read() dipanggil, operasi I/O dijalankan di latar belakang, lalu task dilanjutkan kembali setelah selesai untuk mengembalikan hasil
  • Pendekatan ini sekaligus memberikan penyederhanaan pengelolaan state dan peningkatan keterbacaan kode

Susunan fitur dan struktur runtime

  • Zio mendukung I/O jaringan dan berkas asinkron penuh, primitive sinkronisasi (mutex, condition variable, dll.), channel bergaya Go, pemantauan sinyal OS, dan lainnya
  • Task dapat dijalankan dalam mode single-thread maupun multi-thread
    • Dalam mode multi-thread, task dapat berpindah antar-thread, sehingga memberikan efek penurunan latensi dan peningkatan penyeimbangan beban
  • Zio mengimplementasikan antarmuka Reader/Writer standar untuk memastikan kompatibilitas dengan pustaka eksternal
Iklan

Performa dan perbandingan

  • Penulis belum merilis benchmark resmi, tetapi menyebut telah mengonfirmasi performa yang lebih cepat daripada Go dan Tokio milik Rust dalam mode single-thread
  • Biaya context switching turun hingga setara pemanggilan fungsi, sehingga kecepatan perpindahannya nyaris gratis
  • Mode multi-thread masih belum sekuat Go/Tokio, tetapi menunjukkan performa serupa atau sedikit lebih cepat
    • Di masa depan, penambahan fitur fairness dapat membuat performanya sedikit menurun

Contoh kode dan pemanfaatan

  • Dokumentasi mencakup contoh kode server HTTP berbasis Zio
    • Menggunakan zio.net.Stream untuk menerima koneksi dan menangani tiap koneksi sebagai task terpisah
    • zio.Runtime mengelola eksekusi task dan penjadwalan I/O
  • Struktur ini memungkinkan penulisan I/O asinkron seperti kode sinkron, sekaligus menghadirkan kontrol alur yang jelas dan pengelolaan pelepasan sumber daya

Rencana ke depan dan makna proyek

  • Melalui Zio, penulis menilai bahwa Zig dapat berkembang melampaui sekadar bahasa untuk kode sistem berperforma tinggi, menjadi bahasa untuk pengembangan aplikasi jaringan yang lengkap
  • Sebagai langkah berikutnya, ia berencana menulis ulang klien NATS berbasis Zio dan mengembangkan pustaka klien/server HTTP berbasis Zio
  • Proyek ini dinilai mendorong perluasan infrastruktur jaringan dan konkurensi dalam ekosistem Zig, serta sebagai upaya membangun model runtime modern yang sebanding dengan Go atau Rust

1 komentar

 
GN⁺ 2025-10-28
Komentar Hacker News
  • Perpindahan konteks memang dikatakan hampir gratis pada level pemanggilan fungsi, tetapi dalam praktiknya tetap ada biaya halus seperti branch predictor yang rusak
    Tidak jelas apakah desain async Zig memakai pasangan call/return dari hardware, atau diterjemahkan berbasis lompatan tidak langsung
    Untuk membuat benchmark yang benar-benar sempurna, perlu membandingkan total waktu eksekusi antara program yang terus-menerus berpindah di antara dua tugas dan program yang sepenuhnya sinkron. Ini pekerjaan yang cukup sulit
    • Dalam coroutine stackless, jika dua tugas terus ditukar di bagian paling bawah call stack, dan kode pergantian stack di-inline, maka penalti ketidakcocokan call/ret sebagian besar bisa dihindari
      Jika bisa mengendalikan compiler, call/ret pada kode I/O juga bisa diubah menjadi lompatan eksplisit
      Dalam jangka panjang, saya berharap CPU mengadopsi meta-predictor agar bisa lebih baik memprediksi coroutine stackful
    • Saat ini async di Zig sudah dihapus dari level bahasa, dan OP mengimplementasikan pergantian task di user space sendiri
    • Saat menguji ping-pong sederhana antar coroutine, saya pernah mendapatkan angka yang sulit dipercaya dibanding solusi lain
    • Async baru akan segera ditambahkan ke Zig, jadi saya menunggu sebelum menggali lebih jauh
      Tulisan terkait: Zig new async I/O
  • Coroutine stackful masuk akal ketika RAM cukup besar
    Saya memakai Zig di lingkungan embedded (ARM Cortex-M4, RAM 256KB), dan menggunakannya untuk memastikan keamanan memori saat interoperasi dengan C
    Saya lebih menyukai async berwarna seperti di Rust. Rasanya menyenangkan karena tampak seperti kode sinkron, tetapi di codebase besar masalahnya adalah makin sulit membedakan fungsi mana yang blocking
    • Sebenarnya semua kode sinkron adalah ilusi yang dibuat perangkat lunak
      CPU tidak benar-benar terblokir saat I/O, dan thread OS sendiri adalah coroutine stackful yang diimplementasikan OS
      Di level bahasa, kita hanya bisa mewujudkan ilusi ini dengan lebih efisien, tetapi hakikatnya sama
    • Zig IO baru nantinya akan menjadi struktur colored dengan cara yang lebih elegan daripada Rust
      Warna suatu fungsi ditentukan oleh apakah ia melakukan I/O, dan saat pemanggilan status async-nya dinyatakan secara eksplisit
      Zig juga menargetkan kemampuan menghitung ukuran stack yang dibutuhkan saat pemanggilan fungsi, sehingga diharapkan dapat mengurangi masalah pemborosan RAM pada coroutine stackful
    • Jadi alasan Zig ingin mengekspresikan I/O secara eksplisit adalah agar bisa melacak fungsi yang blocking
  • Ada pendapat bahwa saat ini masih terlalu dini untuk mengadopsi Zig. Model I/O sedang banyak berubah, dan kesannya butuh beberapa tahun lagi
    • Saya juga meninggalkan Zig pada 2020 karena alasan serupa.
      Namun proyeknya tetap sangat aktif, dan saya menilai positif bahwa mereka memprioritaskan desain yang benar dibanding rilis cepat
      Saat ini saya memakai Go atau C sambil menunggu 1.0
    • Beberapa tahun berlalu dengan cepat. Zig sudah cukup layak dipakai. Yang ingin pakai akan pakai, yang tidak ya tidak
    • Memang ini saat yang kurang bagus. Perubahan I/O besar dijadwalkan untuk 0.16, dan bahkan penulisnya sendiri belum memakai fitur terbaru
      Saya juga akan menunggu 0.16 untuk pekerjaan yang berfokus pada I/O
    • Namun jika pekerjaannya terkait I/O, memakai antarmuka buffered reader/writer di Zig 0.15 kemungkinan tidak akan banyak berubah
    • Justru menurut saya sekarang bukan waktu yang salah. Yang berubah besar bukan bahasanya, melainkan Zig sedang menambahkan API std.Io baru yang kuat
      Kode lama tetap berjalan, dan API baru lebih ergonomis serta lebih cepat
      Saya juga memindahkan proyek lama saya ke API Reader/Writer baru, dan kodenya jadi jauh lebih rapi
  • Saya masih heran kenapa async berbasis callback menjadi standar
    Pendekatan seperti libtask terlihat jauh lebih bersih
    Rust juga mengadopsi async berbasis callback, tetapi saya tidak begitu paham alasannya
    Referensi: libtask
    • Coroutine stackless bisa diimplementasikan di dalam bahasa dan keunggulannya adalah interaksi yang dapat diprediksi dengan fitur yang sudah ada
      Namun jika stack ditangani langsung, ini bisa berbenturan dengan penanganan eksepsi, GC, debugger, dan sebagainya
      Karena sulit juga menggabungkan perubahan seperti ini di level LLVM, dari sudut pandang perancang bahasa ada banyak batasan praktis
    • Hasil riset Microsoft untuk standar C++ menyimpulkan bahwa coroutine stackless memiliki overhead memori yang jauh lebih kecil dan memberi kebebasan lebih besar dalam desain executor
    • Kekurangan pendekatan zio atau libtask adalah ukuran stack harus diperkirakan sendiri
      Terlalu kecil akan overflow, terlalu besar memboroskan memori
      Ukuran stack yang dibutuhkan juga berbeda di tiap platform, sehingga muncul masalah portabilitas
      Jika isu Zig #157 terselesaikan, pendekatan ini tampaknya akan menjadi lebih baik
    • Untuk kasus seperti libtask, ukuran stack thread tidak jelas dan jauh lebih besar daripada state async pada umumnya
    • Async Rust bukan callback, melainkan berbasis polling
      Artinya, ada tiga cara mengimplementasikan async
      1. Berbasis callback (Node.js, Swift)
      2. Berbasis stackful (Go, libtask)
      3. Berbasis polling (Rust)
        Rust diubah menjadi state machine statis lalu runtime melakukan polling
        Stackful sangat boros memori, dan pengelolaan ukuran stack-nya sulit
        Untuk menghindari itu, Rust memilih struktur stackless, dan Zig nantinya akan memungkinkan memilih kedua pendekatan tersebut
        Referensi: kode coroutine zio
  • Pembacaan TCP bisa saja blocking selama sebulan, jadi saya penasaran bagaimana bentuk antarmuka timeout I/O
    • Pada socket TCP, timeout baca/tulis bisa diatur dengan setsockopt
      Zig menyediakan lapisan API POSIX
      Referensi: dokumentasi setsockopt
    • Saat ini std.Io.Reader di Zig belum mengenali timeout
      Saya sedang membayangkan struktur yang bekerja seperti asyncio.timeout di Python
      Contoh kode:
      var timeout: zio.Timeout = .init;
      defer timeout.cancel(rt);
      timeout.set(rt, 10);
      const n = try reader.interface.readVec(&data);
      
    • Kebanyakan framework async mengabaikan timeout dan cancellation
      Padahal justru itulah bagian yang paling sulit
  • Di Scala sudah ada library konkurensi bernama ZIO
    Referensi: zio.dev
  • Belakangan ini saya terkesan dengan Tokio di Rust, dan jika di Zig juga bisa mengimplementasikan konkurensi gaya Go tanpa GC, saya benar-benar ingin mencobanya
    • Go bisa memakai trik seperti stack yang bisa berkembang tanpa batas berkat GC
      Namun Zig tetap mengesankan karena meskipun bahasa level rendah, ia bisa mengekspresikan API level tinggi dengan rapi
  • Saya pertama kali mengenal Zig dari situs web Bun. Belakangan ini perkembangannya memang sangat cepat
  • Di versi C++ lama saya mengimplementasikan I/O asinkron dengan Qt, tetapi kali ini beralih ke Go
    Baik Zig maupun Go sama-sama baru mendapatkan binding Qt
    • Go: miqt
    • Zig: libqt6zig
      Saya ingin binding untuk Rust. cxx-qt adalah satu-satunya proyek yang masih dipelihara, tetapi saya tidak ingin memakai QML atau CMake. Saya ingin memakai Qt hanya dengan Rust + Cargo
  • Di Scala juga sudah ada framework terkenal bernama ZIO, jadi saya merasa penamaan memang sulit