PID dan mailbox

Pengiriman pesan asinkron ke PID, selective receive, dan perilaku mailbox.

Daftar isi

Topik ini merinci jalur yang dilalui pesan Erlang: PID sebagai alamat proses, operator ! yang mengirim tanpa menunggu, antrean mailbox dengan urutan kedatangan, dan selective receive yang memungkinkan proses memilih pesan tertentu dari antreannya. Semua contoh dilakukan terhadap proses shell sendiri sehingga setiap perilaku antrean terlihat tanpa proses tambahan.

PID sebagai alamat#

Setiap proses memiliki PID (process identifier) yang unik selama hidupnya, dan PID itulah alamat dasar untuk mengirim pesan. Nilai yang tercetak <0.92.0> terdiri atas tiga bilangan: nomor node, nomor internal proses, dan nomor serial. Fungsi self/0 mengembalikan PID proses pemanggil, dan inilah cara proses menunjuk dirinya sendiri ketika mengirim pesan atau memasukkan alamatnya ke dalam permintaan. PID dapat disimpan di variabel, ditaruh di dalam tuple, dikirim ke proses lain, dan dibandingkan kesetaraannya.

Mengirim tanpa menunggu#

Operator ! mengirim pesan ke mailbox penerima dan langsung kembali. Pengirim tidak menunggu penerimaan, tidak menunggu balasan, dan tidak mendapat tanda terima. Pengiriman selalu tampak berhasil dari sudut pandang bahasa, sebagaimana akan dijelaskan pada topik link dan monitor untuk sisi kegagalan proses penerima. Sesi berikut membuat proses shell mengirim dua pesan ke dirinya sendiri:

erlang Mengirim ke diri sendiri dan membaca antrean
Erlang/OTP 29 [erts-17.1.1] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1] [jit:ns]

Eshell V17.1.1 (press Ctrl+G to abort, type help(). for help)
1> self() ! pesan_a.
pesan_a
2> self() ! pesan_b.
pesan_b
3> receive X -> X end.
pesan_a
4> flush().
Shell got pesan_b
ok

Nilai kembalian ! adalah pesannya sendiri, sehingga prompt mencetak kembali apa yang dikirim. receive X -> X end mengambil pesan pertama yang cocok, yaitu pesan_a, karena mailbox memproses pesan sesuai urutan kedatangan. Fungsi flush/0 kemudian menunjukkan pesan_b masih menunggu di antrean dan mengosongkannya. Mailbox adalah antrean first in, first out: pesan yang dibaca tanpa seleksi diambil sesuai urutan kedatangannya.

Selective receive#

receive dengan pola spesifik tidak harus mengambil pesan paling depan. Ia menyusuri mailbox dari depan, melewati pesan yang tidak cocok, dan mengambil pesan pertama yang cocok dengan polanya:

erlang Memilih pesan tertentu dari antrean
5> self() ! {tiket, 1}.
{tiket,1}
6> self() ! {tiket, 2}.
{tiket,2}
7> receive {tiket, N} -> N end.
1
8> flush().
Shell got {tiket,2}
ok

receive {tiket, N} -> N end mengambil pesan {tiket,1}, yaitu yang paling depan, dan flush/0 menunjukkan {tiket,2} masih menunggu. Kekuatan selective receive muncul saat antrean berisi campuran pesan: satu receive dapat melompati pesan lain untuk mengambil balasan yang dicari, dan pesan yang dilewati tetap berada di antrean dengan urutan aslinya untuk dibaca kemudian. Mekanisme inilah yang memungkinkan proses menunggu balasan permintaan tertentu sementara pesan lain tetap aman.

Akibat seleksi terhadap antrean#

Kekuatan selective receive membawa biaya yang perlu dipahami sejak awal. Pesan yang dilewati tetap menghabiskan memori dan pemeriksaan, sehingga proses yang menerima banjir pesan tetapi hanya mencari satu jenis pesan tertentu akan menyusuri antrean yang tumbuh setiap kali receive dijalankan. Pembandingan antara satu pola dan antrean panjang diulang pada setiap pemanggilan, dan inilah masalah performa yang lazim diwaspadai pada sistem produksi. Dua kebiasaan menahan biaya ini: menjaga pesan yang menunggu tetap sedikit dengan memproses pesan segera, dan menyertakan penanda unik seperti nomor referensi pada permintaan-balasan agar pola pencarian tepat sasaran. Modul OTP behaviour pada topik gen_server memakai keduanya sebagai bagian dari desainnya.

Antrean tanpa batas#

Mailbox tidak memiliki batas ukuran: proses yang sibuk bekerja atau tidak membaca mailbox sama sekali akan menampung pesan yang datang tanpa batas, dan memori tumbuh mengikuti antreannya. Kondisi ini bisa diukur langsung dengan process_info/2:

erlang Mengukur panjang antrean mailbox
1> c(layan).
{ok,layan}
2> P = layan:mulai().
<0.92.0>
3> [P ! spam || _ <- lists:seq(1, 5)].
[spam,spam,spam,spam,spam]
4> process_info(P, message_queue_len).
{message_queue_len,5}

Layanan layan tidak pernah membaca pesan spam, sehingga kelima pesan itu menumpuk dan message_queue_len melaporkannya apa adanya. Di sistem nyata, nilai ini adalah salah satu indikator pertama yang dipantau saat layanan lambat, karena antrean yang terus tumbuh adalah tanda proses penerima tidak sanggup mengikuti laju pengirim. Penanggulangannya beragam, dari mempercepat penerima hingga menerapkan backpressure, dan semua upaya perbaikan itu berangkat dari angka yang sama.

Ringkasan#

  • PID adalah alamat unik setiap proses, dan self/0 memberi PID proses pemanggil.
  • Operator ! mengirim asinkron: nilai kembaliannya adalah pesan itu sendiri dan pengirim tidak menunggu apa pun.
  • Mailbox menyerahkan pesan sesuai urutan kedatangan saat receive tidak menyeleksi.
  • Selective receive menyusuri mailbox dan mengambil pesan pertama yang cocok dengan pola, sementara pesan yang dilewati tetap menunggu di antrean.
  • Antrean yang menumpuk membuat selective receive mahal, sehingga pesan perlu segera diproses dan permintaan-balasan memakai penanda unik.

Referensi#