Untuk jumlah soket yang sangat kecil (bervariasi tergantung pada perangkat keras Anda, tentu saja, tetapi kita berbicara tentang sesuatu di urutan 10 atau kurang), pilih dapat mengalahkan epoll dalam penggunaan memori dan kecepatan runtime. Tentu saja, untuk sejumlah kecil soket, kedua mekanisme tersebut sangat cepat sehingga Anda tidak terlalu peduli dengan perbedaan ini di sebagian besar kasus.
Namun satu klarifikasi. Baik pilih dan skala epoll secara linier. Namun, perbedaan besar adalah bahwa API yang menghadap ke ruang pengguna memiliki kerumitan yang didasarkan pada hal-hal yang berbeda. Biaya select
panggilan kira-kira sama dengan nilai deskriptor file bernomor tertinggi yang Anda berikan. Jika Anda memilih pada satu fd, 100, maka itu kira-kira dua kali lebih mahal daripada memilih pada satu fd, 50. Menambahkan lebih banyak fds di bawah yang tertinggi tidaklah cukup gratis, jadi ini sedikit lebih rumit daripada ini dalam praktiknya, tapi ini adalah perkiraan pertama yang baik untuk sebagian besar implementasi.
Biaya epoll lebih mendekati jumlah deskriptor file yang benar-benar memiliki acara di dalamnya. Jika Anda memantau 200 deskriptor file, tetapi hanya 100 yang memiliki peristiwa di dalamnya, Anda (sangat kasar) hanya membayar untuk 100 deskriptor file aktif tersebut. Di sinilah epoll cenderung menawarkan salah satu keunggulan utamanya dibandingkan pilihan. Jika Anda memiliki seribu klien yang sebagian besar menganggur, maka ketika Anda menggunakan pilih Anda masih membayar untuk seribu klien tersebut. Namun, dengan epoll, sepertinya Anda hanya punya sedikit - Anda hanya membayar yang aktif pada waktu tertentu.
Semua ini berarti epoll akan mengurangi penggunaan CPU untuk sebagian besar beban kerja. Sejauh penggunaan memori berjalan, itu sedikit dilempar. select
berhasil merepresentasikan semua informasi yang diperlukan dengan cara yang sangat kompak (satu bit per deskriptor file). Dan batasan FD_SETSIZE (biasanya 1024) tentang berapa banyak deskriptor file yang dapat Anda gunakan select
berarti Anda tidak akan pernah menghabiskan lebih dari 128 byte untuk masing-masing dari tiga set fd yang dapat Anda gunakan denganselect
(baca, tulis, pengecualian). Dibandingkan dengan maksimal 384 byte itu, epoll adalah semacam babi. Setiap deskriptor file diwakili oleh struktur multi-byte. Namun, secara absolut, itu tetap tidak akan menggunakan banyak memori. Anda dapat mewakili sejumlah besar deskriptor file dalam beberapa lusin kilobyte (kira-kira 20k per 1000 file deskriptor, menurut saya). Dan Anda juga dapat membuang fakta bahwa Anda harus menghabiskan semua 384 byte tersebut dengan select
jika Anda hanya ingin memantau satu deskriptor file tetapi nilainya kebetulan 1024, sedangkan dengan epoll Anda hanya menghabiskan 20 byte. Tetap saja, semua angka ini cukup kecil, jadi tidak ada bedanya.
Dan ada juga manfaat lain dari epoll, yang mungkin sudah Anda ketahui, tidak terbatas pada deskriptor file FD_SETSIZE. Anda dapat menggunakannya untuk memantau deskriptor file sebanyak yang Anda miliki. Dan jika Anda hanya memiliki satu deskriptor file, tetapi nilainya lebih besar dari FD_SETSIZE, epoll juga berfungsi dengan itu, tetapi select
tidak.
Secara acak, saya juga baru-baru ini menemukan satu kelemahan kecil epoll
dibandingkan dengan select
atau poll
. Meskipun tidak satu pun dari ketiga API ini mendukung file normal (yaitu, file pada sistem file), select
dan poll
kurangnya dukungan ini seperti melaporkan deskriptor seperti yang selalu dapat dibaca dan selalu dapat ditulisi. Hal ini membuat mereka tidak cocok untuk semua jenis I / O sistem file non-pemblokiran yang berarti, program yang menggunakan select
atau poll
dan kebetulan menemukan deskriptor file dari sistem file setidaknya akan terus beroperasi (atau jika gagal, itu tidak akan terjadi karena dari select
atau poll
), meskipun itu mungkin tidak dengan performa terbaik.
Di sisi lain, epoll
akan gagal dengan cepat dengan kesalahan ( EPERM
, tampaknya) ketika diminta untuk memantau deskriptor file tersebut. Sebenarnya, ini hampir tidak salah. Ini hanya menandakan kurangnya dukungan secara eksplisit. Biasanya saya akan memuji kondisi kegagalan eksplisit, tetapi yang ini tidak berdokumen (sejauh yang saya tahu) dan menghasilkan aplikasi yang benar-benar rusak, daripada yang hanya beroperasi dengan kinerja yang berpotensi terdegradasi.
Dalam praktiknya, satu-satunya tempat yang pernah saya lihat ini muncul adalah saat berinteraksi dengan stdio. Seorang pengguna mungkin mengarahkan stdin atau stdout dari / ke file normal. Padahal sebelumnya stdin dan stdout akan menjadi pipa - didukung oleh epoll saja - itu kemudian menjadi file normal dan epoll gagal dengan keras, melanggar aplikasi.
poll
kelengkapan?man select
) Kernel Linux tidak memberlakukan batasan tetap, tetapi implementasi glibc membuat fd_set menjadi tipe ukuran tetap, dengan FD_SETSIZE didefinisikan sebagai 1024, dan makro FD _ * () beroperasi sesuai dengan batas itu. Untuk memantau deskriptor file yang lebih besar dari 1023, gunakan poll (2) sebagai gantinya. Di CentOS 7 saya telah melihat masalah di mana kode saya sendiri gagal memilih () karena kernel mengembalikan pegangan file> 1023 dan saat ini saya sedang melihat masalah yang berbau seperti Twisted mengenai masalah yang sama.Dalam pengujian di perusahaan saya, satu masalah dengan epoll () muncul, jadi satu biaya dibandingkan untuk memilih.
Ketika mencoba membaca dari jaringan dengan waktu tunggu, membuat epoll_fd (bukan FD_SET), dan menambahkan fd ke epoll_fd, jauh lebih mahal daripada membuat FD_SET (yang merupakan malloc sederhana).
Sesuai jawaban sebelumnya, karena jumlah FD dalam proses menjadi besar, biaya select () menjadi lebih tinggi, tetapi dalam pengujian kami, bahkan dengan nilai fd di 10.000, pilih masih menjadi pemenang. Ini adalah kasus di mana hanya ada satu fd yang ditunggu oleh thread, dan hanya mencoba mengatasi fakta bahwa jaringan membaca, dan menulis jaringan, tidak timeout saat menggunakan model thread pemblokiran. Tentu saja, model thread pemblokiran berkinerja rendah dibandingkan dengan sistem reaktor non-pemblokiran, tetapi ada kalanya, untuk berintegrasi dengan basis kode lama tertentu, diperlukan.
Kasus penggunaan semacam ini jarang terjadi pada aplikasi berkinerja tinggi, karena model reaktor tidak perlu membuat epoll_fd baru setiap saat. Untuk model di mana epoll_fd berumur panjang --- yang jelas lebih disukai untuk desain server berkinerja tinggi apa pun --- epoll adalah pemenang yang jelas dalam segala hal.
sumber
select()
jika Anda memiliki nilai deskriptor file dalam rentang 10k + - kecuali Anda mengkompilasi ulang setengah sistem Anda untuk mengubah FD_SETSIZE - jadi saya bertanya-tanya bagaimana strategi ini bekerja sama sekali. Untuk skenario yang Anda gambarkan, saya mungkin akan melihatpoll()
mana yang lebih miripselect()
daripada yang sebenarnyaepoll()
- tetapi menghapus batasan FD_SETSIZE.FD_SETSIZE
adalah konstanta waktu kompilasi yang ditetapkan saat library C Anda dikompilasi. Jika Anda mendefinisikannya ke nilai yang berbeda ketika Anda membangun aplikasi Anda, maka aplikasi Anda dan pustaka C tidak akan setuju dan semuanya akan berjalan buruk. Jika Anda memiliki referensi yang mengklaim aman untuk didefinisikan ulang,FD_SETSIZE
saya akan tertarik untuk melihatnya.