Saya baru-baru ini mendengar beberapa orang mengatakan bahwa di Linux, hampir selalu lebih baik menggunakan proses daripada thread, karena Linux sangat efisien dalam menangani proses, dan karena ada begitu banyak masalah (seperti penguncian) yang terkait dengan utas. Namun, saya curiga, karena sepertinya utas dapat memberikan peningkatan kinerja yang cukup besar dalam beberapa situasi.
Jadi pertanyaan saya adalah, ketika dihadapkan pada situasi yang dapat ditangani dengan baik oleh thread dan proses, haruskah saya menggunakan proses atau thread? Misalnya, jika saya menulis server web, haruskah saya menggunakan proses atau utas (atau kombinasi)?
linux
performance
multithreading
process
pengguna17918
sumber
sumber
Jawaban:
Linux menggunakan model threading 1-1, dengan (ke kernel) tidak ada perbedaan antara proses dan utas - semuanya hanyalah tugas yang dapat dijalankan. *
Di Linux, panggilan sistem
clone
mengkloning tugas, dengan tingkat berbagi yang dapat dikonfigurasi, di antaranya adalah:CLONE_FILES
: bagikan tabel deskriptor file yang sama (alih-alih membuat salinan)CLONE_PARENT
: jangan mengatur hubungan orangtua-anak antara tugas baru dan yang lama (jika tidak, childgetppid()
= parent'sgetpid()
)CLONE_VM
: berbagi ruang memori yang sama (alih-alih membuat salinan COW )fork()
panggilanclone(
berbagi paling sedikit)
danpthread_create()
panggilanclone(
berbagi paling banyak)
. **fork
Biaya sedikit lebih banyak daripadapthread_create
karena menyalin tabel dan membuat pemetaan SAP untuk memori, tetapi pengembang kernel Linux telah mencoba (dan berhasil) meminimalkan biaya-biaya tersebut.Beralih di antara tugas, jika mereka berbagi ruang memori yang sama dan berbagai tabel, akan sedikit lebih murah daripada jika mereka tidak dibagikan, karena data mungkin sudah dimuat dalam cache. Namun, berpindah tugas masih sangat cepat walaupun tidak ada yang dibagikan - ini adalah hal lain yang coba dipastikan oleh pengembang kernel Linux (dan berhasil memastikan).
Bahkan, jika Anda menggunakan sistem multi-prosesor, tidak berbagi sebenarnya dapat bermanfaat bagi kinerja: jika setiap tugas berjalan pada prosesor yang berbeda, sinkronisasi memori bersama adalah mahal.
* Sederhana.
CLONE_THREAD
menyebabkan pengiriman sinyal untuk dibagikan (yang perluCLONE_SIGHAND
, yang berbagi tabel penangan sinyal).** Sederhana. Ada keduanya
SYS_fork
danSYS_clone
syscalls, tetapi di kernel,sys_fork
dansys_clone
keduanya adalah pembungkus yang sangat tipis di sekitardo_fork
fungsi yang sama , yang itu sendiri adalah pembungkus tipis di sekitarcopy_process
. Ya, persyaratannyaprocess
,,thread
dantask
digunakan secara bergantian di kernel Linux ...sumber
socket
,bind
,listen
,fork
, dan kemudian memiliki beberapa prosesaccept
koneksi pada soket mendengarkan sama. Suatu proses dapat berhenti menerima jika sibuk, dan kernel akan merutekan koneksi yang masuk ke proses lain (jika tidak ada yang mendengarkan, kernel akan mengantri atau jatuh, tergantung padalisten
backlog). Anda tidak memiliki kendali lebih besar atas distribusi pekerjaan dari itu, tetapi biasanya itu cukup baik!clone()
menentukan sumber daya mana yang dibagikan. Suatu tugas juga dapatunshare()
sumber daya pada suatu titik waktu kemudian.task_struct
untuk setiap tugas. Ini sering disebut "proses" di seluruh kode kernel, tetapi sesuai dengan setiap utas yang dapat dijalankan. Tidak adaprocess_struct
; jika sekelompoktask_struct
s dihubungkan olehthread_group
daftar mereka , maka mereka "proses" yang sama untuk userspace. Ada sedikit penanganan khusus "utas", misalnya semua utas saudara dihentikan pada fork dan exec, dan hanya utas "utama" yang munculls /proc
. Setiap utas dapat diakses melalui/proc/pid
, apakah itu terdaftar/proc
atau tidak.clone(CLONE_THREAD | CLONE_VM | CLONE_SIGHAND))
akan memberi Anda "utas" baru yang tidak membagikan direktori kerja, file, atau kunci, sementaraclone(CLONE_FILES | CLONE_FS | CLONE_IO)
akan memberi Anda "proses" yang berfungsi . Sistem yang mendasarinya menciptakan tugas dengan kloning;fork()
danpthread_create()
hanya fungsi perpustakaan yang memanggilclone()
berbeda (seperti yang saya tulis dalam jawaban ini).Linux (dan memang Unix) memberi Anda pilihan ketiga.
Opsi 1 - proses
Buat executable mandiri yang menangani beberapa bagian (atau semua bagian) aplikasi Anda, dan jalankan secara terpisah untuk setiap proses, misalnya program menjalankan salinannya sendiri untuk mendelegasikan tugas.
Opsi 2 - utas
Buat executable mandiri yang dimulai dengan utas tunggal dan buat utas tambahan untuk melakukan beberapa tugas
Opsi 3 - garpu
Hanya tersedia di Linux / Unix, ini sedikit berbeda. Proses bercabang benar-benar adalah prosesnya sendiri dengan ruang alamatnya sendiri - tidak ada yang dapat dilakukan anak (biasanya) untuk memengaruhi ruang alamat orang tua atau saudara kandungnya (tidak seperti utas) - sehingga Anda mendapatkan kekokohan tambahan.
Namun, halaman memori tidak disalin, itu adalah copy-on-write, jadi lebih sedikit memori yang digunakan daripada yang Anda bayangkan.
Pertimbangkan program server web yang terdiri dari dua langkah:
Jika Anda menggunakan utas, langkah 1 akan dilakukan sekali, dan langkah 2 dilakukan di banyak utas. Jika Anda menggunakan proses "tradisional", langkah 1 dan 2 perlu diulang untuk setiap proses, dan memori untuk menyimpan konfigurasi dan data runtime digandakan. Jika Anda menggunakan fork (), maka Anda dapat melakukan langkah 1 sekali, dan kemudian fork (), meninggalkan data runtime dan konfigurasi dalam memori, tidak tersentuh, tidak disalin.
Jadi sebenarnya ada tiga pilihan.
sumber
Itu tergantung pada banyak faktor. Proses lebih berat daripada thread, dan memiliki biaya startup dan shutdown yang lebih tinggi. Komunikasi antarproses (IPC) juga lebih keras dan lebih lambat daripada komunikasi antar cetakan.
Sebaliknya, proses lebih aman dan lebih aman daripada utas, karena setiap proses berjalan dalam ruang alamat virtualnya sendiri. Jika satu proses crash atau memiliki buffer overrun, itu tidak mempengaruhi proses lain sama sekali, sedangkan jika sebuah thread crash, itu akan menghapus semua utas lainnya dalam proses tersebut, dan jika sebuah thread memiliki buffer overrun, ia membuka lubang keamanan di semua utas.
Jadi, jika modul aplikasi Anda sebagian besar dapat berjalan secara independen dengan sedikit komunikasi, Anda mungkin harus menggunakan proses jika Anda mampu membayar biaya startup dan shutdown. Hit kinerja IPC akan minimal, dan Anda akan sedikit lebih aman terhadap bug dan lubang keamanan. Jika Anda membutuhkan setiap bit kinerja yang dapat Anda peroleh atau memiliki banyak data bersama (seperti struktur data yang kompleks), ikuti utas.
sumber
Yang lain telah membahas pertimbangannya.
Mungkin perbedaan penting adalah bahwa dalam proses Windows berat dan mahal dibandingkan dengan utas, dan di Linux perbedaannya jauh lebih kecil, sehingga persamaannya seimbang pada titik yang berbeda.
sumber
Sekali waktu ada Unix dan di Unix tua yang baik ini ada banyak overhead untuk proses, jadi apa yang dilakukan beberapa orang pintar adalah membuat utas, yang akan berbagi ruang alamat yang sama dengan proses induk dan mereka hanya perlu konteks yang dikurangi switch, yang akan membuat konteks switch lebih efisien.
Dalam Linux kontemporer (2.6.x) tidak ada banyak perbedaan dalam kinerja antara perubahan konteks dari suatu proses dibandingkan dengan utas (hanya hal-hal MMU yang ditambahkan untuk utas). Ada masalah dengan ruang alamat bersama, yang berarti bahwa pointer yang salah dalam utas dapat merusak memori proses induk atau utas lain dalam ruang alamat yang sama.
Suatu proses dilindungi oleh MMU, sehingga penunjuk yang salah hanya akan menyebabkan sinyal 11 dan tidak ada korupsi.
Secara umum saya akan menggunakan proses (tidak banyak konteks beralih overhead di Linux, tetapi perlindungan memori karena MMU), tetapi pthreads jika saya memerlukan kelas penjadwal waktu nyata, yang merupakan secangkir teh yang berbeda secara bersamaan.
Menurut Anda mengapa utas memiliki keuntungan kinerja yang begitu besar di Linux? Apakah Anda memiliki data untuk ini, atau hanya mitos?
sumber
Seberapa erat tugas Anda?
Jika mereka dapat hidup secara independen satu sama lain, maka gunakan proses. Jika mereka saling mengandalkan, maka gunakan utas. Dengan begitu Anda dapat membunuh dan memulai kembali proses yang buruk tanpa mengganggu pengoperasian tugas lainnya.
sumber
Untuk memperumit masalah lebih lanjut, ada yang namanya penyimpanan thread-lokal , dan memori bersama Unix.
Penyimpanan thread-local memungkinkan setiap utas untuk memiliki instance terpisah dari objek global. Satu-satunya waktu saya menggunakannya adalah ketika membangun lingkungan emulasi di linux / windows, untuk kode aplikasi yang berjalan dalam RTOS. Dalam RTOS setiap tugas adalah proses dengan ruang alamatnya sendiri, dalam lingkungan persaingan, setiap tugas adalah utas (dengan ruang alamat bersama). Dengan menggunakan TLS untuk hal-hal seperti lajang, kami dapat memiliki contoh terpisah untuk setiap utas, sama seperti di bawah lingkungan RTOS 'nyata'.
Memori bersama dapat (jelas) memberi Anda manfaat kinerja memiliki banyak proses mengakses memori yang sama, tetapi dengan biaya / risiko harus menyinkronkan proses dengan benar. Salah satu cara untuk melakukannya adalah memiliki satu proses membuat struktur data dalam memori bersama, dan kemudian mengirim pegangan ke struktur itu melalui komunikasi antar-proses tradisional (seperti pipa bernama).
sumber
Dalam karya terbaru saya dengan LINUX adalah satu hal yang harus diperhatikan adalah perpustakaan. Jika Anda menggunakan utas, pastikan ada perpustakaan yang Anda gunakan di utas aman. Ini membakar saya beberapa kali. Terutama libxml2 tidak aman di luar kotak. Itu dapat dikompilasi dengan thread aman tetapi bukan itu yang Anda dapatkan dengan aptitude install.
sumber
Saya harus setuju dengan apa yang telah Anda dengar. Saat kami membandingkan cluster kami (
xhpl
dan semacamnya), kami selalu mendapatkan kinerja yang jauh lebih baik dengan proses di atas utas.</anecdote>
sumber
Keputusan antara utas / proses sedikit tergantung pada apa yang akan Anda gunakan. Salah satu manfaat dari suatu proses adalah memiliki PID dan dapat dibunuh tanpa juga menghentikan orang tua.
Untuk contoh dunia nyata dari server web, apache 1.3 yang digunakan hanya mendukung beberapa proses, tetapi di 2.0 mereka menambahkan abstraksi sehingga Anda dapat beralih di antara keduanya. Komentar tampaknya untuk setuju bahwa proses lebih kuat tapi benang dapat memberikan sedikit memagut kinerja yang lebih baik (kecuali untuk jendela di mana kinerja untuk proses menyebalkan dan Anda hanya ingin menggunakan benang).
sumber
Untuk sebagian besar kasus, saya lebih suka proses daripada utas. utas dapat berguna ketika Anda memiliki tugas yang relatif lebih kecil (proses overhead >> waktu yang diambil oleh masing-masing unit tugas yang dibagi) dan ada kebutuhan berbagi memori di antara mereka. Pikirkan array yang besar. Juga (offtopic), perhatikan bahwa jika utilisasi CPU Anda 100 persen atau mendekati itu, tidak akan ada manfaat dari multithreading atau pemrosesan. (pada kenyataannya itu akan memburuk)
sumber
Threads -> Threads berbagi ruang memori, ini adalah abstraksi dari CPU, itu ringan. Proses -> Proses memiliki ruang memori sendiri, ini adalah abstraksi komputer. Untuk memparalelkan tugas, Anda perlu mengabstraksi CPU. Namun keuntungan menggunakan proses di atas utas adalah keamanan, stabilitas sementara utas menggunakan memori yang lebih rendah daripada proses dan menawarkan latensi yang lebih rendah. Contoh dalam hal web adalah chrome dan firefox. Dalam hal Chrome, masing-masing tab adalah proses baru maka penggunaan memori chrome lebih tinggi daripada firefox, sementara keamanan dan stabilitas yang diberikan lebih baik daripada firefox. Keamanan di sini yang disediakan oleh chrome lebih baik, karena setiap tab adalah proses baru, tab yang berbeda tidak dapat menyelinap ke ruang memori dari proses yang diberikan.
sumber
Saya pikir semua orang telah melakukan pekerjaan dengan baik menanggapi pertanyaan Anda. Saya hanya menambahkan informasi lebih lanjut tentang utas versus proses di Linux untuk mengklarifikasi dan merangkum beberapa tanggapan sebelumnya dalam konteks kernel. Jadi, tanggapan saya berkaitan dengan kode khusus kernel di Linux. Menurut dokumentasi Kernel Linux, tidak ada perbedaan yang jelas antara utas versus proses kecuali utas menggunakan ruang alamat virtual bersama tidak seperti proses. Perhatikan juga, Kernel Linux menggunakan istilah "tugas" untuk merujuk pada proses dan utas secara umum.
"Tidak ada struktur internal yang mengimplementasikan proses atau utas, sebaliknya ada struct task_struct yang menggambarkan unit penjadwalan abstrak yang disebut tugas"
Juga menurut Linus Torvalds, Anda TIDAK boleh berpikir tentang proses versus utas sama sekali dan karena terlalu membatasi dan satu-satunya perbedaan adalah COE atau Konteks Eksekusi dalam hal "pisahkan ruang alamat dari orang tua" atau ruang alamat bersama. Bahkan ia menggunakan contoh server web untuk menyampaikan maksudnya di sini (yang sangat merekomendasikan membaca).
Kredit penuh untuk dokumentasi kernel linux
sumber
Jika Anda perlu berbagi sumber daya, Anda harus menggunakan utas.
Juga pertimbangkan fakta bahwa sakelar konteks antar thread jauh lebih murah daripada sakelar konteks antar proses.
Saya tidak melihat alasan untuk secara eksplisit menjalankan proses terpisah kecuali jika Anda memiliki alasan yang baik untuk melakukannya (keamanan, uji kinerja terbukti, dll ...)
sumber