Python Async, mengapa masih belum menjadi arus utama?
(tonybaloney.github.io)Python Async, mengapa masih belum menjadi arus utama?
asyncio di Python adalah alat yang kuat yang dapat secara dramatis meningkatkan efisiensi program dengan mengurangi waktu tunggu di lingkungan dengan banyak pekerjaan I/O (input/output). Namun, terlepas dari berbagai kelebihannya, tidak semua pengembang Python menggunakannya secara aktif, dan ada beberapa alasan mendasar di baliknya.
1. Kepala jadi lebih rumit: beban kognitif
Hambatan terbesar adalah kompleksitas. Kode sinkron itu intuitif karena kita cukup mengikuti alur eksekusinya dari atas ke bawah secara berurutan, seperti membaca buku.
Namun, kode asinkron berbeda. Bayangkan seorang koki yang saat membuat pasta, sambil menunggu mi direbus (waktu tunggu), di sisi lain membuat saus, lalu di waktu senggang merapikan sayuran. Hasil akhirnya memang bisa selesai lebih cepat, tetapi di kepala koki itu, ia harus terus memperhatikan status banyak pekerjaan seperti “mi-nya sudah matang sejauh mana?” dan “sausnya gosong atau tidak?”.
Karena alur eksekusi kode berpindah-pindah ke sana kemari seperti ini, menjadi sulit untuk memahami pekerjaan mana yang sedang berjalan dan mana yang sedang menunggu. Ini membuat proses debugging, terutama saat bug muncul, menjadi sangat rumit untuk melacak penyebabnya.
2. Ekosistem yang terpisah sendiri: kompatibilitas library
Masalah lain di Python adalah ekosistem library yang terbagi antara mode “sinkron” dan “asinkron”. Banyak library terkenal dan nyaman digunakan (misalnya library standar untuk permintaan HTTP requests atau banyak ORM) hanya bekerja secara sinkron.
Jika library sinkron digunakan secara keliru di dalam kode asinkron, maka selama kode sinkron itu berjalan, “event loop” yang merupakan keunggulan utama async akan ikut berhenti total. Ini seperti sudah membuat banyak lajur jalan tetapi hanya memakai satu lajur saja, sehingga memakai async jadi kehilangan maknanya. Untuk mengatasi masalah ini, pengembang harus mempelajari dan menerapkan library terpisah yang mendukung async (aiohttp, asyncpg, dll.), yang membuat learning curve menjadi lebih curam.
3. Hanya bisa menghajar satu per satu: GIL (Global Interpreter Lock)
GIL (Global Interpreter Lock) adalah salah satu karakteristik lama Python, yaitu mekanisme yang membatasi agar dalam satu proses, meskipun ada banyak thread, tetap hanya satu thread saja yang bisa berjalan pada saat yang sama. Karena asyncio bekerja pada satu thread, ia tidak berbenturan langsung dengan GIL, tetapi keberadaan GIL membatasi ruang pemanfaatan async.
asyncio dioptimalkan untuk memanfaatkan waktu tunggu I/O (menunggu respons jaringan, menunggu pembacaan file, dan sebagainya). Namun, jika ada pekerjaan yang intensif CPU dengan perhitungan yang sangat kompleks di dalam fungsi async, maka seluruh event loop akan berhenti sampai perhitungan itu selesai. Selama waktu itu, pekerjaan I/O lain tidak bisa berbuat apa-apa selain menunggu. Pada akhirnya, untuk pekerjaan yang benar-benar membutuhkan pemrosesan paralel, tetap ada batasan bahwa teknik lain seperti multiprocessing masih harus digunakan.
4. Harapan untuk masa depan: Python 3.14 dan penghapusan GIL
Namun, ada kabar yang sangat menjanjikan terkait keterbatasan ini. Yaitu gerakan menuju penghapusan GIL secara opsional, yang mulai diperkenalkan secara eksperimental sejak Python 3.13 dan diharapkan menjadi lebih matang pada versi 3.14.
Perubahan yang didorong melalui proposal bernama PEP 703 ini bertujuan agar pengembang dapat menjalankan kode Python tanpa GIL jika mereka menginginkannya. Jika ini benar-benar terwujud, Python pun akan memungkinkan multithreading sejati, di mana banyak thread dapat memanfaatkan banyak inti CPU secara bersamaan.
Ini dapat menghasilkan sinergi yang sangat besar ketika digunakan bersama asyncio. Pekerjaan I/O dapat ditangani secara efisien dengan asyncio, sementara pekerjaan CPU yang membutuhkan banyak komputasi bisa dilempar ke thread terpisah untuk diproses secara paralel tanpa batasan GIL. Perubahan ini diperkirakan akan menjadi titik balik besar bagi ekosistem Python, dan banyak yang berharap bahwa ini akan meruntuhkan berbagai hambatan yang selama ini menghalangi adopsi pemrograman async.
9 komentar
Menurut saya GIL agak muncul tiba-tiba di sini.. bahkan kalau GIL dihapus pun
jika ingin menggunakan multithread baik untuk kasus I/O bound maupun CPU bound,
mungkin akan lebih baik mengadopsi alternatif lain selain Python..
Saya juga merasa
asynciomemang agak kurang disukai oleh orang-orang yang mendalami Python.Saya rasa saya cukup sering mendengar pendapat bahwa
geventseharusnya yang menjadi arus utama.Saya setuju bahwa sulit berharap arah penanganan GIL saat ini akan menjadi sesuatu yang tidak kalah baik dibandingkan dengan "alternatif lain",
namun menurut saya, mengatakan bahwa kita harus mengadopsi alternatif selain Python seharusnya mengarah bukan pada nada bahwa tidak ada masalah, melainkan pada nada bahwa memang ada masalah.
Saya cukup sering memakai asyncio.. dan ini lumayan berguna.. ada keterbatasan karena pembatalan task dibuat sebagai edge-triggered (bukan level-triggered), tetapi sebenarnya tidak banyak kasus menulis kode yang sadar terhadap pembatalan task sekaligus menanganinya dengan graceful, dan masalah yang lebih besar adalah event loop memegang weak reference ke task sehingga task bisa hilang karena GC.. namun itu bisa diselesaikan dengan structured concurrency.
Untuk sebagian besar pekerjaan I/O utama, tidak ada masalah mencari library yang mendukung asyncio..
GIL? Tidak terlalu berkaitan.. pendekatan memakai asyncio untuk menjalankan pekerjaan CPU intensive secara paralel sendiri terasa agak aneh.. kalau GIL membaik, itu akan berguna untuk multithreading CPU intensive.. async itu bertujuan menjalankan bagian yang bottleneck di I/O seefisien mungkin...
Bagaimanapun, kesimpulannya.. memang ada beberapa masalah desain, tetapi untuk mencapai tujuan, saya memakainya di production tanpa masalah berarti dan berjalan dengan baik.
Apakah Anda pernah mengalami task dipungut oleh GC?
Tentu saja saya juga sudah bosan menggunakan
asynciodi production, tetapi saya masih belum cukup puas dengan pengalaman penggunaannya saat ini sampai bisa menilainya sebagai, 'saya memanfaatkannya dengan baik.'asynciosaat ini dirancang dengan asumsi adanya GIL, jadi bisa dibilang ini semacam strategi untuk menghindari GIL, sehingga GIL sendiri tidak benar-benar berinteraksi denganasyncio.Namun, jika dilihat dari perspektif seluruh pemrograman concurrency yang berjalan berbasis
asyncio, saya rasa mengatakan bahwa GIL tidak relevan pada akhirnya menjadi semacam pernyataan seperti, "Ya wajar saja tidak bisa, namanya juga Python."Saya akan pakai joblib saja
Masalah Asyncio bukanlah tingkat kesulitan pemrograman asinkron yang memang sulit, melainkan kualitasnya yang rendah. Desain yang membuang konsistensi dan universalitas memang bukan hal langka di Python, tetapi untuk hal seperti
ProactorEventLoop, bug yang menyebabkan gangguan layanan dan sudah dilaporkan 5 tahun lalu masih juga belum diperbaiki.Dari posisi orang yang terpaksa harus memakainya, tulisan seperti ini benar-benar sulit untuk ditertawakan begitu saja.
Tentu saja, alasan yang lebih besar mungkin adalah karena sejak awal manfaat yang bisa diperoleh akibat GIL lebih kecil dibandingkan lingkungan lain.
Saya rasa ungkapan bahwa tanpa GIL bisa menghasilkan sinergi itu nyaris menyesatkan. Kalau seorang pelari yang kehilangan satu kaki dipasangi kaki palsu meski tetap tidak nyaman, apakah itu bisa disebut 'sinergi'?