Langsung ke konten

Arsip

Concurrency

72 artikel
Rekayasa Perangkat Lunak 19 Sep 2026 5 min read

EPOLLET Menjadikan Readiness sebagai Kontrak Transisi State

Descriptor yang didaftarkan dengan EPOLLET dapat tetap readable setelah sebuah event dikirim tanpa muncul lagi pada epoll_wait() berikutnya. Kernel melaporkan transisi readiness; kernel tidak menjanjikan pengulangan notifikasi yang sama hanya karena masih ada data yang belum dibaca. Perbedaan ini menjadikan edge-triggered epoll sebagai kontrak transisi state antara kernel dan event loop. Konsekuensinya bersifat struktural. Handler tidak dapat memperlakukan satu event sebagai izin untuk satu read() lalu langsung kembali ke wait loop. Pada edge-triggered monitoring, handler harus memperhitungkan seluruh state I/O yang segera tersedia sebelum bergantung pada transisi berikutnya.

Rekayasa Perangkat Lunak 19 Sep 2026 6 min read

Circuit Breaker Membatasi Trafik Kegagalan Lintas Panggilan Service

Circuit breaker mengubah keputusan admission untuk panggilan keluar sebelum dependency menerimanya. Pada state closed, panggilan diteruskan dan hasilnya menjadi input bagi kebijakan kegagalan. Setelah kebijakan tersebut terpicu, breaker masuk ke state open dan menolak panggilan berikutnya secara lokal. Setelah interval pemulihan yang dikonfigurasi berakhir, sejumlah terbatas panggilan probe dapat menguji apakah dependency sudah dapat dipakai kembali. Mekanisme ini berbeda dari retry. Retry mengirim percobaan lain setelah sebuah percobaan gagal. Breaker dapat mencegah sebuah percobaan dikirim sama sekali. Menggabungkan keduanya tanpa urutan yang presisi dapat memperbesar trafik saat terjadi gangguan atau mempertahankan breaker dalam state open berdasarkan sinyal yang tidak merepresentasikan kondisi dependency.

Rekayasa Perangkat Lunak 19 Sep 2026 7 min read

Cara Runtime Bahasa Memakai Core CPU: Thread, Goroutine, Worker, dan Proses

CPU dengan banyak core tidak membuat kode aplikasi menjadi paralel dengan sendirinya. Sistem operasi memang dapat menjadwalkan beberapa thread pada saat yang sama, tetapi bahasa dan runtime menentukan bagaimana pekerjaan aplikasi mencapai thread tersebut. Perbedaan ini menjelaskan mengapa Go, Rust, C++, Java, JavaScript, dan PHP sama-sama dapat memakai mesin multicore meskipun model pemrogramannya sangat berbeda. Pertanyaan yang lebih berguna bukan sekadar apakah sebuah bahasa “multithreaded”. Yang perlu dilihat adalah bagaimana satu unit pekerjaan aplikasi berubah menjadi sesuatu yang dapat dijadwalkan oleh sistem operasi.

Rekayasa Perangkat Lunak 19 Sep 2026 5 min read

Bounded Queue Mengubah Overload Menjadi Keputusan Admission yang Eksplisit

Queue di antara producer dan consumer yang lebih lambat dapat menyerap perbedaan laju untuk sementara. Queue tidak dapat menghapus perbedaan tersebut. Jika arrival terus lebih cepat daripada completion, setiap item yang diterima menambah pekerjaan yang belum selesai. Unbounded queue membiarkan state itu menumpuk sampai resource lain menjadi batas efektif, sering kali memory atau timeout eksternal. Bounded queue memindahkan batas tersebut ke interface. Setelah capacity habis, admission harus menghasilkan sesuatu yang dapat diamati: menunggu ruang tersedia, menolak pekerjaan baru, membuang pekerjaan tertentu, atau mengalihkannya ke tempat lain. Karena itu, capacity queue dan perilaku saat penuh menjadi bagian dari kontrak overload sistem.

Rekayasa Perangkat Lunak 18 Sep 2026 5 min read

SO_REUSEPORT Memindahkan Distribusi Listener ke Seleksi Socket

SO_REUSEPORT memungkinkan beberapa socket Linux AF_INET atau AF_INET6 melakukan bind pada alamat dan port lokal yang sama selama setiap anggota memenuhi aturan reuse-port. Pada listener TCP, distribusi koneksi masuk berpindah ke tahap sebelum accept(): kernel memilih satu listener dari grup reuse-port, lalu listener tersebut menerima koneksi pada accept queue miliknya. Pada UDP, seleksi menentukan socket yang menerima datagram masuk. Batas concurrency ini berbeda dari beberapa thread yang berbagi satu listening file description. Setiap anggota reuse-port adalah socket terpisah dengan descriptor, queue, status polling, dan lifecycle sendiri.

Rekayasa Perangkat Lunak 18 Sep 2026 4 min read

pidfd Mengikat Operasi Proses ke Referensi Kernel yang Stabil

PID numerik menamai sebuah proses hanya selama PID tersebut masih dialokasikan kepadanya. Setelah proses berhenti dan di-reap, Linux dapat memakai kembali nomor itu untuk proses lain. PID file descriptor, atau pidfd, menyimpan referensi kernel ke task tertentu, sehingga operasi berikutnya dapat menargetkan task tersebut tanpa melakukan resolusi ulang terhadap PID numeriknya. Perbedaan ini menghilangkan satu kelas race time-of-check/time-of-use dari pengelolaan proses. pidfd tidak membuat proses tetap hidup, tidak memberi izin tambahan, dan tidak mengubah seluruh operasi proses menjadi API descriptor yang portabel.

Linux 18 Sep 2026 6 min read

membarrier Memindahkan Biaya Pengurutan Memori ke Jalur Koordinasi yang Jarang

Full hardware memory barrier pada jalur yang sangat sering dieksekusi dapat membebankan biaya pada setiap operasi, meskipun koordinasi lintas thread hanya terjadi sesekali. Linux membarrier() menyediakan penempatan biaya yang berbeda: jalur koordinasi yang jarang dapat meminta event pengurutan pada sekumpulan thread tertentu, sementara jalur yang sering dapat cukup memakai pengurutan pada level compiler dalam desain yang sesuai. Mekanisme ini bukan pengganti umum untuk atomic, lock, atau memory model suatu bahasa pemrograman. membarrier() adalah primitive sinkronisasi khusus Linux untuk desain yang correctness-nya sudah memiliki pasangan yang presisi antara jalur yang sering dan jalur koordinasi yang jarang.

Linux 18 Sep 2026 4 min read

EPOLLEXCLUSIVE Membatasi Wakeup pada epoll Instance yang Bersaing

Satu socket yang ready dapat membangunkan beberapa thread ketika setiap thread menunggu pada epoll instance berbeda yang memantau socket tersebut. Linux menyediakan EPOLLEXCLUSIVE untuk mempersempit fan-out wakeup itu: di antara epoll instance yang mendaftarkan target dengan flag tersebut, sebuah readiness event membangunkan satu atau lebih instance, bukan semuanya. Batas semantiknya sengaja lebih lemah daripada “tepat satu waiter.” EPOLLEXCLUSIVE mengubah seleksi notifikasi antar-epoll instance. Flag ini tidak memindahkan kepemilikan file descriptor, tidak menserialkan seluruh I/O, dan tidak menjamin hanya satu thread yang dapat melihat pekerjaan yang berguna.

Rekayasa Perangkat Lunak 18 Sep 2026 5 min read

EPOLLEXCLUSIVE Membatasi Wakeup di Antara Instance epoll yang Bersaing

EPOLLEXCLUSIVE mengubah waiter epoll mana yang dibangunkan saat beberapa instance epoll memantau target yang sama. Tanpa flag ini, sebuah readiness event dapat dikirim ke setiap instance epoll yang terpasang. Dengan registrasi eksklusif, Linux dapat membangunkan subset yang lebih kecil sehingga scheduling redundan berkurang pada konfigurasi yang jika tidak demikian dapat memicu thundering herd. Flag ini mengubah distribusi wakeup. Ia tidak memberikan kepemilikan permanen atas target descriptor, tidak menserialisasi I/O, dan tidak menjamin tepat satu thread aplikasi mengonsumsi setiap unit pekerjaan.

Rekayasa Perangkat Lunak 18 Sep 2026 4 min read

CLOSE_RANGE_UNSHARE Mengisolasi Pembersihan Tabel Descriptor

Sebuah thread yang bersiap melewati batas execve() dapat perlu menghapus seluruh file descriptor di atas sekumpulan kecil descriptor yang dipertahankan ketika thread lain masih memakai tabel descriptor yang sama. Penutupan descriptor satu per satu membuka race: thread lain dapat mengalokasikan descriptor baru ke interval tersebut saat pembersihan masih berjalan. Di Linux, close_range() dengan CLOSE_RANGE_UNSHARE mengubah batas pemakaian bersama tabel sebelum operasi range diterapkan. Perilaku ini penting karena nomor file descriptor hanya merupakan indeks pada tabel descriptor proses. Dengan CLONE_FILES, beberapa task dapat merujuk tabel yang sama, sehingga penutupan oleh satu task mengubah visibilitas descriptor bagi seluruh task yang berbagi tabel tersebut. CLOSE_RANGE_UNSHARE memberi task pemanggil tabel descriptor privat sebagai bagian dari operasi.

Rekayasa Perangkat Lunak 17 Sep 2026 6 min read

userfaultfd Memindahkan Resolusi Missing Page ke User Space

Sebuah thread dapat mengakses alamat virtual yang valid lalu berhenti sebelum akses selesai karena page tersebut belum memiliki backing yang present. Pada range yang didaftarkan dengan UFFDIO_REGISTER_MODE_MISSING, Linux dapat melaporkan fault itu melalui userfaultfd alih-alih menyelesaikannya sepenuhnya di kernel. Manager di user space kemudian menentukan isi page yang menjadi terlihat sebelum akses yang tertahan dilanjutkan. Mekanisme ini memindahkan kendali atas satu bagian penanganan page fault. Kernel tetap mendeteksi fault, memvalidasi virtual memory area, menahan eksekusi yang mengalami fault, dan memasang mapping melalui antarmuka UFFDIO_*. User space memperoleh kendali atas isi dan waktu resolusi untuk fault yang terdaftar.

Rekayasa Perangkat Lunak 17 Sep 2026 6 min read

pidfd Linux Mengubah Identitas Proses Menjadi Handle yang Dapat Dipantau

PID Linux adalah angka dari namespace yang dapat digunakan ulang. pidfd berbeda: ia adalah file descriptor yang merujuk ke proses tertentu. Perbedaan itu mengubah pengelolaan proses dari lookup berulang berdasarkan nama numerik menjadi operasi terhadap handle yang dipertahankan kernel dan identitasnya tidak diam-diam berpindah ketika PID didaur ulang. Perbedaannya paling terlihat pada supervisor, launcher, sandbox, dan service manager yang mempertahankan referensi proses melintasi pekerjaan asynchronous. PID numerik dapat tetap valid secara sintaksis setelah proses asli keluar, tetapi kemudian mengidentifikasi proses lain. pidfd menjaga referensi tetap terikat pada objek proses asli dan juga dapat berpartisipasi dalam event loop berbasis descriptor.

Linux 17 Sep 2026 5 min read

O_APPEND Menggabungkan Posisi Akhir dengan Setiap Write

O_APPEND mengubah write dari dua tindakan yang dapat dipisahkan menjadi satu operasi terpadu: Linux menempatkan open file description pada akhir file saat ini lalu melakukan write sebagai satu langkah atomik. Sifat ini penting ketika beberapa writer menulis ke regular file yang sama. Urutan lseek(fd, 0, SEEK_END) lalu write(fd, ...) tidak memiliki semantik append yang sama karena writer lain dapat mengubah file di antara kedua system call tersebut. Status append berada pada open file description O_APPEND adalah file status flag. File status flag disimpan pada open file description, bukan pada integer file descriptor itu sendiri.

Rekayasa Perangkat Lunak 17 Sep 2026 5 min read

Linux userfaultfd Mengubah Page Fault Menjadi Protokol Userspace

Sebuah thread dapat mengakses alamat virtual yang valid lalu berhenti sebelum akses tersebut selesai karena komponen userspace lain diberi tanggung jawab untuk menyelesaikan page fault. Dengan Linux userfaultfd, rentang memori tertentu dapat mengubah fault menjadi pesan descriptor sementara thread yang mengalami fault tetap tertahan sampai operasi resolusi yang sesuai memungkinkan eksekusi berlanjut. Mekanisme ini bukan pengganti subsistem virtual memory kernel. Kernel tetap mendeteksi fault, memvalidasi rentang yang terdaftar, menahan jalur eksekusi yang terdampak, dan menjalankan operasi page table yang diminta manager. Batas yang berbeda terletak pada partisipasi userspace dalam menentukan kapan dan dengan isi apa sebuah fault diselesaikan.

Rekayasa Perangkat Lunak 17 Sep 2026 6 min read

Linux signalfd Memindahkan Delivery Signal ke Readiness File Descriptor

Linux signalfd Memindahkan Delivery Signal ke Readiness File Descriptor signalfd() mengubah antarmuka konsumsi untuk signal Linux tertentu. Alih-alih mengatur agar asynchronous signal handler berjalan saat signal tersebut dikirim, sebuah proses dapat memblokir signal lalu menerima informasinya dengan membaca file descriptor. Descriptor itu dapat dipantau melalui poll(), epoll, dan mekanisme readiness terkait, sehingga penanganan signal dapat memakai batas dispatch yang sama dengan socket, pipe, timer, dan objek pollable lain. Mekanisme ini tidak menggantikan semantik signal Linux. Pembentukan signal, delivery yang diarahkan ke proses atau thread, mask, pending state, serta aturan antrean standard signal dan real-time signal tetap berlaku. signalfd mengubah antarmuka untuk mengonsumsi signal yang berstatus pending dan termasuk dalam mask miliknya.

Rekayasa Perangkat Lunak 17 Sep 2026 5 min read

Linux io_uring Memisahkan Submission dari Kepemilikan Completion

Linux io_uring Memisahkan Submission dari Kepemilikan Completion Sebuah request io_uring dapat tetap in flight setelah aplikasi selesai membentuk submission queue entry. Kondisi ini menciptakan batas lifetime yang tidak ada pada call sinkron sederhana: metadata request dapat menjadi stabil saat submission, sedangkan memori yang menjadi payload I/O masih dapat diakses sampai operasi selesai. Completion queue karena itu bukan sekadar kanal hasil. Untuk banyak operasi, completion menandai titik ketika state operasi milik aplikasi dapat di-reclaim atau digunakan kembali.

Rekayasa Perangkat Lunak 17 Sep 2026 5 min read

Linux eventfd Membuat Status Counter Dapat Dipantau

Linux eventfd dapat menggabungkan banyak notifikasi ke dalam satu counter yang dikelola kernel sambil tetap dapat digunakan dengan poll(), select(), dan epoll. Writer menambahkan nilai unsigned 64-bit ke counter; readiness menyatakan apakah status tersebut dapat dikonsumsi. Interface ini membawa status aritmetika, bukan byte stream atau antrean pesan individual. Perbedaan tersebut penting pada batas proses dan thread. Sebuah wakeup menyatakan bahwa counter bukan nol. Wakeup itu tidak mempertahankan jumlah operasi write, identitas writer, atau urutan di antara sumber notifikasi yang terpisah.

Rekayasa Perangkat Lunak 17 Sep 2026 8 min read

Edge Triggering epoll Mengubah Readiness Menjadi Kewajiban untuk Menguras

Registrasi epoll edge-triggered dapat berhenti menghasilkan notifikasi sementara byte yang belum dibaca masih tersisa di socket atau pipe. Descriptor tetap dapat digunakan untuk I/O, tetapi event loop sudah mengonsumsi notifikasi yang terkait dengan transisi readiness. Jika handler hanya membaca sebagian data yang tersedia lalu kembali ke epoll_wait(), tidak ada keharusan muncul transisi baru, sehingga byte yang tertunda dapat dibiarkan tanpa diproses tanpa batas. Perilaku ini membuat EPOLLET lebih dari sekadar preferensi notifikasi. Ia mengubah kontrak antara ready list kernel dan application state. Loop level-triggered dapat terus menerima descriptor selama kondisi I/O yang diminta tetap benar. Loop edge-triggered harus mempertahankan cukup local state untuk memperlakukan event yang diterima sebagai kewajiban menguras I/O nonblocking yang saat itu tersedia, biasanya sampai operasi mengembalikan EAGAIN.

Go 16 Sep 2026 4 min read

Reuse Go WaitGroup Memerlukan Boundary Wait yang Sudah Selesai

sync.WaitGroup dapat digunakan kembali setelah sebuah wait phase selesai, tetapi task set independen baru tidak boleh dimulai selama call Wait dari phase sebelumnya masih aktif. Boundary-nya adalah return dari setiap Wait sebelumnya, bukan sekadar saat internal task counter mencapai nol. Constraint ini penting ketika satu instance WaitGroup dipertahankan lintas batch, epoch, request wave, atau coordination cycle berulang. Reuse didukung, tetapi phase tidak boleh overlap pada transisi counter dari nol menjadi positif.

Linux 16 Sep 2026 4 min read

Readiness epoll Edge-Triggered Memerlukan Draining

Consumer epoll edge-triggered dapat terblokir ketika data yang belum dibaca masih tersimpan di buffer. Kegagalan ini muncul ketika sebuah event dikonsumsi, hanya sebagian input yang tersedia dibaca, lalu event loop kembali ke epoll_wait() dengan harapan menerima notifikasi lain untuk byte yang tersisa. Perilaku ini mengikuti langsung semantik EPOLLET. Notifikasi edge-triggered melaporkan perubahan readiness, bukan terus-menerus melaporkan kondisi ready. Setelah sebuah transisi readiness menghasilkan event, membiarkan file descriptor tetap ready tidak dengan sendirinya menciptakan transisi baru.

Go 16 Sep 2026 4 min read

Go sync.Cond Wait Memeriksa Ulang Shared State

sync.Cond.Wait melanjutkan eksekusi setelah notification, tetapi notification tidak menyatakan bahwa kondisi khusus milik caller masih true ketika goroutine memperoleh lock kembali. Shared predicate tetap menjadi source of truth, sehingga waiter memeriksanya lagi setiap kali Wait kembali. Boundary ini memisahkan notification dari state. Signal dan Broadcast mengumumkan bahwa state yang relevan mungkin telah berubah; keduanya tidak memindahkan ownership state tersebut atau memesannya untuk waiter tertentu. Wait membuka lock lalu memperolehnya kembali Sebuah Cond terkait dengan Locker, umumnya *sync.Mutex. Caller memegang lock tersebut saat memeriksa shared state. Jika predicate false, Wait secara atomik membuka locker dan menangguhkan caller. Sebelum Wait kembali, ia mengunci locker lagi.

Go 16 Sep 2026 5 min read

Go singleflight Hanya Membagikan Hasil yang Sedang In-Flight

singleflight.Group menekan eksekusi function duplikat hanya selama operasi dengan key yang sama masih in-flight. Caller concurrent dapat menerima satu hasil bersama, tetapi caller yang datang setelah completion akan memulai eksekusi baru. Karena itu group adalah mekanisme request coalescing, bukan result cache. Boundary ini memengaruhi cache fill, metadata refresh, backend read, dan operasi berbasis key lain yang dapat menerima burst pekerjaan concurrent identik. Group dapat mengurangi tekanan simultan pada backing operation tanpa memperpanjang lifetime value yang dikembalikan.

Go 16 Sep 2026 5 min read

Go errgroup SetLimit Memblokir Submitter saat Batas Concurrency Tercapai

errgroup.Group.SetLimit dapat memblokir goroutine yang memanggil Group.Go. Limit diterapkan sebelum worker goroutine baru dimulai, sehingga group yang penuh menerapkan backpressure pada saat task submission alih-alih membangun internal queue. Perilaku ini penting ketika submission merupakan bagian dari control path lain. Loop yang tampak meluncurkan pekerjaan secara asynchronous dapat berhenti di g.Go(...) sampai salah satu active function selesai. Limit berada pada admission Zero-value errgroup.Group tidak memiliki concurrency limit. Setelah SetLimit(n), paling banyak n function yang dimulai oleh Go aktif secara bersamaan. Negative limit mengembalikan unlimited admission, sedangkan zero limit mencegah setiap pemanggilan Go berikutnya memulai function.

Python 09 Sep 2026 8 min read

Matikan Queue Worker asyncio dengan Bersih

Pool worker asynchronous sering dimulai dengan pola sederhana: producer memasukkan job ke asyncio.Queue, consumer melakukan loop pada get(), dan aplikasi menunggu join() sebelum keluar. Bagian yang canggung adalah shutdown. Desain lama biasanya memasukkan satu nilai sentinel ke queue untuk setiap worker, membatalkan consumer setelah join(), atau mempertahankan stop event terpisah. Setiap pendekatan dapat bekerja, tetapi masing-masing menambahkan protokol kedua di samping queue itu sendiri. Python 3.13 menambahkan asyncio.Queue.shutdown() dan exception asyncio.QueueShutDown. Keduanya memungkinkan queue merepresentasikan lifecycle-nya sendiri: terbuka untuk producer, dalam proses shutdown sementara pekerjaan yang ada dikuras, lalu akhirnya tertutup bagi consumer.