Ringkasan:
- Selama 15 tahun terakhir, modul
subprocessPython dan librarypsutiltelah menggunakan pendekatan 'Busy-loop polling' yang tidak efisien saat menunggu proses berakhir (wait()), dengan mengulangsleepdanwaitpid. - Pendekatan ini menimbulkan wake-up CPU yang tidak perlu, konsumsi baterai, masalah latensi dalam mendeteksi berakhirnya proses, dan skalabilitas yang buruk saat memantau banyak proses.
- Melalui pembaruan terbaru, di Linux kini diterapkan 'penantian berbasis event (event-driven waiting)' yang sesungguhnya dengan memanfaatkan
pidfd_open()danpoll(), sementara di BSD/macOS menggunakankqueue(). - Windows sudah menggunakan
WaitForSingleObject, sehingga tidak ada perubahan di sana, tetapi pada sistem POSIX, context switching yang tidak perlu dihilangkan dan penggunaan CPU mendekati '0'.
Ringkasan detail:
1. Masalah yang bertahan selama 15 tahun: Busy-loop polling
Sejak parameter timeout ditambahkan ke subprocess.Popen.wait() pada Python 3.3, library standar Python dan library psutil yang banyak digunakan telah memakai cara yang tidak efisien untuk menunggu proses selesai.
Logika lama sederhana, tetapi tidak efisien:
- Periksa status proses dengan
waitpid(WNOHANG)(non-blocking) - Jika belum selesai,
sleep()sebentar (dengan exponential backoff) - Kembali ke langkah 1 dan ulangi
# Cara lama (kode konseptual)
import time, os
def wait_busy(pid, timeout):
delay = 0.0001
while True:
# Memeriksa apakah proses sudah berakhir (polling)
if os.waitpid(pid, os.WNOHANG) == (pid, status):
return status
time.sleep(delay)
delay = min(delay * 2, 0.040) # tingkatkan waktu tunggu hingga maksimum 40ms
Pendekatan ini memiliki 3 kelemahan fatal berikut.
- Wake-up CPU: Seberapa pun lama waktu tunggunya ditingkatkan, sistem tetap harus bangun secara berkala untuk memeriksa status, sehingga membuang siklus CPU dan mengonsumsi daya.
- Latensi: Tak terhindarkan ada jeda waktu antara saat proses benar-benar berakhir dan saat sistem bangun dari
sleeplalu mendeteksinya. - Skalabilitas: Dalam lingkungan server yang harus memantau ratusan hingga ribuan proses sekaligus, overhead ini meningkat tajam.
2. Solusi: Penantian berbasis event untuk sistem POSIX
Semua sistem POSIX menyediakan mekanisme (select, poll, epoll, kqueue) untuk mendeteksi perubahan status pada file descriptor. Baru-baru ini, Python dan psutil ditingkatkan untuk memanfaatkan mekanisme ini dalam mendeteksi PID proses.
- Linux: Memanfaatkan system call
pidfd_open()yang diperkenalkan pada kernel Linux 5.3 tahun 2019. Ini mengembalikan file descriptor yang menunjuk ke PID proses, lalu dapat didaftarkan kepoll()atauepoll()untuk memantau event berakhirnya proses. (Ditambahkan ke modulossejak Python 3.9) - BSD / macOS: Menggunakan filter
EVFILT_PROCpada system callkqueue()untuk memantau event proses secara efisien. - Windows: Sudah mendukung penantian berbasis event melalui API
WaitForSingleObject, sehingga tidak ada perubahan.
3. Peningkatan performa dan hasil
Dengan perubahan ini, saat wait() dipanggil, dari sudut pandang kernel proses masuk ke status 'Interruptible sleep'. Artinya, proses dapat menunggu diam di ruang kernel tanpa mengonsumsi CPU sama sekali, lalu langsung bangun ketika sinyal berakhirnya proses terjadi.
Hasil benchmark dengan /usr/bin/time -v dan alat serupa menunjukkan bahwa dibanding cara lama, context switching yang tidak perlu berkurang drastis, dan kecepatan deteksi berakhirnya proses juga meningkat secara langsung. Pembaruan ini telah diterapkan pada library psutil dan inti CPython, sehingga ke depannya para pengembang Python bisa menikmati peningkatan performa ini tanpa perlu mengubah kode mereka sendiri.
Belum ada komentar.