Kinerja IPC: Pipa Bernama vs Soket

114

Semua orang sepertinya mengatakan pipa bernama lebih cepat daripada soket IPC. Seberapa cepat mereka? Saya lebih suka menggunakan soket karena mereka dapat melakukan komunikasi dua arah dan sangat fleksibel tetapi akan lebih memilih kecepatan daripada fleksibilitas jika jumlahnya cukup banyak.

pengguna19745
sumber
10
Jarak tempuh Anda akan bervariasi. :) Profil penggunaan tipikal untuk aplikasi yang Anda maksud, dan pilih yang lebih baik dari keduanya. Kemudian profil pipa anonim, soket domain dan keluarga lain, semaphore dan memori bersama atau antrian pesan (SysV dan POSIX), sinyal waktu nyata dengan kata data, atau apa pun. pipe(2)(er mkfifo(3),?) mungkin pemenangnya, tetapi Anda tidak akan tahu sampai Anda mencobanya.
pilcrow
2
Antrian pesan SysV FTW! Saya tidak tahu apakah mereka cepat, saya hanya memiliki titik lemah untuk mereka.
Tom Anderson
4
Apa yang dimaksud dengan "kecepatan" dalam kasus ini? Kecepatan transfer data keseluruhan? Atau latensi (seberapa cepat byte pertama sampai ke penerima)? Jika Anda ingin transfer data lokal yang cepat, maka sulit untuk mengalahkan memori bersama. Jika latensi adalah masalah, maka pertanyaannya menjadi lebih menarik ...
Ian Ni-Lewis

Jawaban:

64

Saya sarankan Anda mengambil jalan yang mudah terlebih dahulu, dengan hati-hati mengisolasi mekanisme IPC sehingga Anda dapat mengubah dari soket ke pipa, tetapi saya pasti akan menggunakan soket terlebih dahulu. Anda harus memastikan kinerja IPC menjadi masalah sebelum melakukan pengoptimalan terlebih dahulu.

Dan jika Anda mendapat masalah karena kecepatan IPC, saya pikir Anda harus mempertimbangkan untuk beralih ke memori bersama daripada menggunakan pipa.

Jika Anda ingin melakukan beberapa pengujian kecepatan transfer, Anda harus mencoba socat , yang merupakan program sangat serbaguna yang memungkinkan Anda membuat hampir semua jenis terowongan.

shodanex.dll
sumber
48

Hasil terbaik yang akan Anda dapatkan dengan solusi Memori Bersama .

Pipa bernama hanya 16% lebih baik dari soket TCP .

Hasil diperoleh dengan pembandingan IPC :

  • Sistem: Linux (Linux ubuntu 4.4.0 x86_64 i7-6700K 4.00GHz)
  • Pesan: 128 byte
  • Jumlah pesan: 1000000

Tolok ukur pipa:

Message size:       128
Message count:      1000000
Total duration:     27367.454 ms
Average duration:   27.319 us
Minimum duration:   5.888 us
Maximum duration:   15763.712 us
Standard deviation: 26.664 us
Message rate:       36539 msg/s

Tolok ukur FIFO (pipa bernama):

Message size:       128
Message count:      1000000
Total duration:     38100.093 ms
Average duration:   38.025 us
Minimum duration:   6.656 us
Maximum duration:   27415.040 us
Standard deviation: 91.614 us
Message rate:       26246 msg/s

Tolok ukur Antrian Pesan:

Message size:       128
Message count:      1000000
Total duration:     14723.159 ms
Average duration:   14.675 us
Minimum duration:   3.840 us
Maximum duration:   17437.184 us
Standard deviation: 53.615 us
Message rate:       67920 msg/s

Tolok ukur Memori Bersama:

Message size:       128
Message count:      1000000
Total duration:     261.650 ms
Average duration:   0.238 us
Minimum duration:   0.000 us
Maximum duration:   10092.032 us
Standard deviation: 22.095 us
Message rate:       3821893 msg/s

Tolok ukur soket TCP:

Message size:       128
Message count:      1000000
Total duration:     44477.257 ms
Average duration:   44.391 us
Minimum duration:   11.520 us
Maximum duration:   15863.296 us
Standard deviation: 44.905 us
Message rate:       22483 msg/s

Tolok ukur soket domain Unix:

Message size:       128
Message count:      1000000
Total duration:     24579.846 ms
Average duration:   24.531 us
Minimum duration:   2.560 us
Maximum duration:   15932.928 us
Standard deviation: 37.854 us
Message rate:       40683 msg/s

Tolok ukur ZeroMQ:

Message size:       128
Message count:      1000000
Total duration:     64872.327 ms
Average duration:   64.808 us
Minimum duration:   23.552 us
Maximum duration:   16443.392 us
Standard deviation: 133.483 us
Message rate:       15414 msg/s
chronoxor
sumber
1
Terima kasih atas pembandingan yang mendetail. Apakah yang Anda maksud adalah "multiprocessing.Queue" dengan "Message Queue"?
ovunccetin
1
Antrian Pesan adalah antrian pesan XSI sistem ( man7.org/linux/man-pages/man0/sys_msg.h.0p.html )
chronoxor
34

Saya akan setuju dengan shodanex, sepertinya Anda terlalu dini mencoba mengoptimalkan sesuatu yang belum bermasalah. Kecuali Anda tahu soket akan menjadi hambatan, saya akan menggunakannya.

Banyak orang yang bersumpah dengan pipa bernama menemukan sedikit penghematan (tergantung pada seberapa baik segala sesuatu yang lain ditulis), tetapi berakhir dengan kode yang menghabiskan lebih banyak waktu memblokir untuk balasan IPC daripada melakukan pekerjaan yang berguna. Tentu, skema non-pemblokiran membantu ini, tetapi itu bisa rumit. Menghabiskan bertahun-tahun membawa kode lama ke zaman modern, saya dapat mengatakan, percepatan hampir nol dalam sebagian besar kasus yang pernah saya lihat.

Jika Anda benar-benar berpikir bahwa soket akan memperlambat Anda, keluarlah dari gerbang menggunakan memori bersama dengan hati-hati memperhatikan cara Anda menggunakan kunci. Sekali lagi, pada kenyataannya, Anda mungkin menemukan percepatan kecil, tetapi perhatikan bahwa Anda menyia-nyiakan sebagian darinya menunggu di kunci pengecualian bersama. Saya tidak akan menganjurkan perjalanan ke neraka futex (yah, tidak cukup lagi di tahun 2015, tergantung pengalaman Anda).

Pound untuk pound, soket (hampir) selalu merupakan cara terbaik untuk menggunakan ruang pengguna IPC di bawah kernel monolitik .. dan (biasanya) yang paling mudah untuk di-debug dan dipelihara.

Tim Pos
sumber
2
mungkin suatu hari nanti di masa depan utopis yang jauh kita akan memiliki kernel yang benar-benar baru, modular, dan modern yang secara implisit menawarkan semua kemampuan (interproses dan lainnya) yang saat ini kita lakukan di atas pecahan kaca ... tapi hei .. orang bisa bermimpi
Gukki5
27

Perlu diingat bahwa soket tidak selalu berarti IP (dan TCP atau UDP). Anda juga dapat menggunakan soket UNIX (PF_UNIX), yang menawarkan peningkatan kinerja yang nyata dibandingkan menghubungkan ke 127.0.0.1

Yuliy
sumber
1
Bagaimana dengan Windows?
Pacerier
1
@Pacerier Sayangnya, Anda tidak dapat membuat soket lokal di Windows dengan cara yang sama seperti namespace abstrak di UNIX. Saya menemukan soket PF_UNIX jauh lebih cepat (> 10%) daripada kebanyakan metode lain yang dijelaskan di halaman ini.
EntangledLoops
1
devblogs.microsoft.com/commandline/af_unix-come-to-windows update, soket Unix tersedia di Windows 10 sekarang.
eri0o
11

Jika Anda tidak membutuhkan kecepatan, soket adalah cara termudah untuk digunakan!

Jika yang Anda lihat adalah kecepatan, solusi tercepat adalah Memori bersama, bukan pipa bernama.

Damien
sumber
8

Untuk komunikasi dua arah dengan pipa bernama:

  • Jika Anda memiliki sedikit proses, Anda dapat membuka dua pipa untuk dua arah (processA2ProcessB dan processB2ProcessA)
  • Jika Anda memiliki banyak proses, Anda dapat membuka pipa masuk dan keluar untuk setiap proses (processAin, processAout, processBin, processBout, processCin, processCout dll)
  • Atau Anda bisa menjadi hybrid seperti biasa :)

Pipa bernama cukup mudah diimplementasikan.

Misalnya saya mengimplementasikan proyek di C dengan pipa bernama, berkat komunikasi berbasis input-output file standar (fopen, fprintf, fscanf ...) itu sangat mudah dan bersih (jika itu juga menjadi pertimbangan).

Saya bahkan mengkodekannya dengan java (saya membuat serial dan mengirim objek ke mereka!)

Pipa bernama memiliki satu kelemahan:

  • mereka tidak berskala pada banyak komputer seperti soket karena mereka bergantung pada sistem file (dengan asumsi sistem file bersama bukanlah pilihan)
daghan
sumber
8

Satu masalah dengan soket adalah mereka tidak memiliki cara untuk membersihkan buffer. Ada sesuatu yang disebut algoritma Nagle yang mengumpulkan semua data dan membilasnya setelah 40ms. Jadi jika itu adalah responsivitas dan bukan bandwidth, Anda mungkin lebih baik menggunakan pipa.

Anda dapat menonaktifkan Nagle dengan opsi soket TCP_NODELAY tetapi kemudian pembacaan tidak akan pernah menerima dua pesan singkat dalam satu panggilan baca.

Jadi mengujinya, saya berakhir dengan semua ini dan mengimplementasikan antrian berbasis pemetaan memori dengan pthread mutex dan semaphore di memori bersama, menghindari banyak panggilan sistem kernel (tetapi hari ini mereka tidak terlalu lambat lagi).

Lothar
sumber
3
"Jadi ujilah" <- kata-kata untuk dijalani.
Koshinae
6

Pipa dan soket yang diberi nama tidak setara secara fungsional; soket menyediakan lebih banyak fitur (mereka dua arah, sebagai permulaan).

Kami tidak dapat memberi tahu Anda mana yang akan berkinerja lebih baik, tetapi saya sangat curiga itu tidak masalah.

Soket domain Unix akan melakukan banyak hal seperti yang dilakukan soket tcp, tetapi hanya pada mesin lokal dan dengan (mungkin sedikit) overhead yang lebih rendah.

Jika soket Unix tidak cukup cepat dan Anda mentransfer banyak data, pertimbangkan untuk menggunakan memori bersama antara klien dan server Anda (yang BANYAK lebih rumit untuk disiapkan).

Unix dan NT keduanya memiliki "Pipa bernama" tetapi keduanya sama sekali berbeda dalam set fiturnya.

MarkR
sumber
1
Nah jika Anda membuka 2 pipa, maka Anda mendapatkan perilaku bidi juga.
Pacerier
4

Anda dapat menggunakan solusi ringan seperti ZeroMQ [ zmq / 0mq ]. Sangat mudah digunakan dan secara dramatis lebih cepat daripada soket.

Amit Vujic
sumber
2
Anda mungkin suka, tebak Amit, karya seni Martin SUSTRIK berikutnya - sesuai dengan POSIX nanomsg. Bagaimanapun, selamat datang & nikmati tempat hebat ini & jadilah Anggota yang Berkontribusi secara aktif.
pengguna3666197