Kapan Anda membutuhkan "ratusan ribu" utas?

31

Erlang, Go, dan Rust semua mengklaim dengan satu atau lain cara bahwa mereka mendukung pemrograman bersamaan dengan "utas" / coroutine murah. The Go FAQ negara:

Praktis untuk membuat ratusan ribu goroutine di ruang alamat yang sama.

The Rust Tutorial mengatakan:

Karena tugas secara signifikan lebih murah untuk dibuat daripada utas tradisional, Rust dapat membuat ratusan ribu tugas bersamaan pada sistem 32-bit yang khas.

Dokumentasi Erlang mengatakan:

Ukuran tumpukan awal default 233 kata cukup konservatif untuk mendukung sistem Erlang dengan ratusan ribu atau bahkan jutaan proses.

Pertanyaan saya: aplikasi macam apa yang membutuhkan banyak utas eksekusi bersamaan? Hanya server web tersibuk yang menerima ribuan pengunjung sekaligus. Aplikasi tipe bos-pekerja / job-dispatching yang saya tulis mencapai hasil yang menurun ketika jumlah utas / proses jauh lebih besar dari jumlah inti fisik. Saya kira mungkin masuk akal untuk aplikasi numerik, tetapi pada kenyataannya kebanyakan orang mendelegasikan paralelisme ke perpustakaan pihak ketiga yang ditulis dalam Fortran / C / C ++, bukan bahasa generasi yang lebih baru ini.

pengguna39019
sumber
5
Saya pikir sumber kebingungan Anda adalah ini: Microthreads ini / tugas / dll terutama tidak dimaksudkan sebagai pengganti untuk OS threads / proses yang Anda bicarakan, juga tidak dimaksudkan untuk digunakan untuk membagi sepotong besar yang mudah diparalelkan dengan jumlah angka. antara beberapa core (seperti yang Anda katakan dengan benar, tidak ada gunanya memiliki 100k utas pada 4 core untuk tujuan itu).
us2012
1
Lalu untuk apa mereka? Mungkin saya naif tetapi saya belum pernah menemukan situasi di mana memperkenalkan coroutine / etc akan menyederhanakan program eksekusi satu thread. Dan saya sudah bisa mencapai tingkat konkurensi "rendah" dengan proses, yang di Linux saya dapat meluncurkan ratusan atau ribuan tanpa berkeringat.
user39019
Tidak masuk akal jika banyak tugas yang benar-benar berfungsi. Itu tidak berarti Anda tidak dapat memiliki banyak tugas yang sebagian besar hanya diblokir menunggu sesuatu terjadi.
Loren Pechtel
5
Ide asynchrony berbasis tugas vs asynchrony berbasis thread adalah untuk mengatakan bahwa kode pengguna harus berkonsentrasi pada tugas - tugas yang perlu terjadi daripada mengelola pekerja yang melakukan tugas-tugas tersebut. Pikirkan utas sebagai pekerja yang Anda pekerjakan; mempekerjakan seorang pekerja itu mahal, dan jika Anda melakukannya, Anda ingin mereka bekerja keras sebanyak mungkin dengan tugas 100%. Banyak sistem dapat dikategorikan memiliki ratusan atau ribuan tugas yang tertunda tetapi Anda tidak perlu ratusan atau ribuan pekerja.
Eric Lippert
Melanjutkan komentar @ EricLippert, ada beberapa situasi di mana ratusan ribu tugas akan ada. Contoh # 1: dekomposisi tugas paralel-data, seperti pemrosesan gambar. Contoh # 2: server yang mendukung ratusan ribu klien, yang masing-masing berpotensi mengeluarkan perintah kapan saja. Setiap tugas akan membutuhkan "konteks eksekusi ringan" sendiri - kemampuan untuk mengingat keadaan apa yang ada di dalamnya (protokol komunikasi), dan perintah yang saat ini dieksekusi, dan sedikit lainnya. Ringan dimungkinkan selama masing-masing memiliki tumpukan panggilan yang dangkal.
rwong

Jawaban:

19

satu kasus penggunaan - websockets:
karena websockets berumur panjang dibandingkan dengan permintaan sederhana, pada server yang sibuk banyak websockets akan terakumulasi dari waktu ke waktu. microthreads memberi Anda pemodelan konseptual yang baik dan juga implementasi yang relatif mudah.

lebih umum, kasus-kasus di mana banyak unit otonom lebih atau kurang menunggu peristiwa tertentu terjadi harus menjadi kasus penggunaan yang baik.

kr1
sumber
15

Mungkin membantu untuk memikirkan apa yang awalnya dirancang untuk dilakukan Erlang, yaitu mengelola telekomunikasi. Kegiatan seperti routing, switching, pengumpulan / agregasi sensor, dll.

Membawa ini ke dunia web - pertimbangkan sistem seperti Twitter . Sistem mungkin tidak akan menggunakan microthreads dalam menghasilkan halaman web, tetapi bisa menggunakannya dalam pengumpulan / caching / distribusi tweet.

Artikel ini mungkin bisa membantu lebih lanjut.

Dave Clausen
sumber
11

Dalam bahasa di mana Anda tidak diizinkan untuk memodifikasi variabel, tindakan sederhana mempertahankan status memerlukan konteks eksekusi yang terpisah (yang kebanyakan orang akan memanggil utas dan Erlang memanggil proses). Pada dasarnya, semuanya adalah pekerja.

Pertimbangkan fungsi Erlang ini, yang mengelola penghitung:

counter(Value) ->
    receive                               % Sit idle until a message is received
        increment -> counter(Value + 1);  % Restart with incremented value
        decrement -> counter(Value - 1);  % Restart with decremented value
        speak     ->
            io:fwrite("~B~n", [Value]),
            counter(Value);               % Restart with unaltered value
        _         -> counter(Value)       % Anything else?  Do nothing.
    end.

Dalam bahasa OO konvensional seperti C ++ atau Java, Anda akan mencapai ini dengan memiliki kelas dengan anggota kelas privat, metode publik untuk mendapatkan atau mengubah statusnya dan objek instantiated untuk setiap penghitung. Erlang menggantikan gagasan objek yang dipakai dengan proses, gagasan metode dengan pesan dan pemeliharaan negara dengan panggilan ekor yang me-restart fungsi dengan nilai apa pun yang membentuk keadaan baru. Manfaat tersembunyi dalam model ini - dan sebagian besar raison d'etre Erlang - adalah bahwa bahasa secara otomatis membuat serialisasi akses ke nilai penghitung melalui penggunaan antrian pesan, membuat kode bersamaan sangat mudah untuk diterapkan dengan tingkat keamanan yang tinggi .

Anda mungkin terbiasa dengan gagasan bahwa switch konteks mahal, yang masih berlaku dari perspektif OS host. Erlang runtime sendiri merupakan sistem operasi kecil yang disetel sehingga peralihan di antara prosesnya sendiri cepat dan efisien, sambil mempertahankan jumlah konteks yang beralih ke OS. Karena alasan ini, memiliki ribuan proses bukanlah masalah dan dianjurkan.

Blrfl
sumber
1
Aplikasi terakhir Anda counter/1harus menggunakan huruf kecil c;) Saya mencoba memperbaikinya, tetapi StackExchange tidak menyukai pengeditan 1 karakter.
d11wtq
4

Pertanyaan saya: aplikasi macam apa yang membutuhkan banyak utas eksekusi bersamaan?

1) Fakta bahwa suatu bahasa "timbangan" berarti ada sedikit kesempatan Anda harus membuang bahasa itu ketika keadaan menjadi semakin rumit. (Ini disebut konsep "Produk Utuh".) Banyak orang membuang Apache untuk Nginx karena alasan ini. Jika Anda berada di dekat "batas keras" yang dikenakan oleh overhead thread, Anda akan merasa takut dan mulai memikirkan cara untuk melewatinya. Situs web tidak pernah dapat memprediksi berapa banyak lalu lintas yang akan mereka peroleh, jadi menghabiskan sedikit waktu untuk membuat hal-hal yang dapat diskalakan adalah masuk akal.

2) Satu goroutine per permintaan hanya permulaan. Ada banyak alasan untuk menggunakan goroutine secara internal.

  • Pertimbangkan aplikasi web dengan permintaan simultan 100-an, tetapi setiap permintaan menghasilkan 100-an permintaan back-end. Contoh nyata adalah agregator mesin pencari. Tetapi hampir semua aplikasi dapat membuat goroutine untuk setiap "area" di layar, lalu menghasilkannya secara independen, bukan berurutan. Misalnya, setiap halaman di Amazon.com terdiri dari 150+ permintaan back-end, disusun hanya untuk Anda. Anda tidak melihat karena mereka paralel, tidak berurutan, dan masing-masing "area" adalah layanan web itu sendiri.
  • Pertimbangkan aplikasi apa pun yang keandalan dan latensinya sangat penting. Anda mungkin ingin setiap permintaan masuk untuk memadamkan beberapa permintaan back-end, dan mengembalikan data mana yang lebih dulu kembali .
  • Pertimbangkan "klien bergabung" yang dilakukan di aplikasi Anda. Alih-alih mengatakan "untuk setiap elemen, dapatkan data", Anda dapat memintal sekelompok goroutine. Jika Anda memiliki banyak DB budak yang harus di-query, secara ajaib Anda akan lebih cepat N kali. Jika tidak, itu tidak akan lebih lambat.

hit semakin berkurang saat jumlah utas / proses jauh lebih besar dari jumlah inti fisik

Kinerja bukan satu-satunya alasan untuk memecah program menjadi CSP . Ini sebenarnya dapat membuat program lebih mudah dipahami, dan beberapa masalah dapat diselesaikan dengan kode yang jauh lebih sedikit.

Seperti pada slide yang ditautkan di atas, memiliki konkurensi dalam kode Anda adalah cara untuk mengatur masalahnya. Tidak memiliki goroutine sama seperti tidak memiliki struktur data Peta / Dictonary / Hash dalam bahasa Anda. Anda bisa bertahan tanpanya. Tetapi begitu Anda memilikinya, Anda mulai menggunakannya di mana-mana, dan itu benar-benar menyederhanakan program Anda.

Di masa lalu, ini berarti pemrograman multithreaded "roll your own". Tapi ini rumit dan berbahaya - masih belum ada banyak alat untuk memastikan Anda tidak membuat balapan. Dan bagaimana Anda mencegah manajer masa depan melakukan kesalahan? Jika Anda melihat program besar / kompleks, Anda akan melihat mereka menghabiskan BANYAK sumber daya ke arah itu.

Karena concurrency bukan bagian kelas dari sebagian besar bahasa, programmer saat ini memiliki titik buta mengapa hal itu berguna bagi mereka. Ini hanya akan menjadi lebih jelas karena setiap ponsel dan jam tangan mengarah ke 1000 core. Pergi kapal dengan alat detektor ras built-in.

BraveNewCurrency
sumber
2

Untuk Erlang adalah umum untuk memiliki satu proses per koneksi atau tugas lainnya. Jadi misalnya server audio streaming mungkin memiliki 1 proses per pengguna yang terhubung.

Erlang VM dioptimalkan untuk menangani ribuan atau bahkan ratusan ribu proses dengan membuat sakelar konteks sangat murah.

Zachary K
sumber
1

Kenyamanan Kembali ketika saya mulai melakukan pemrograman multi-threaded, saya melakukan banyak simulasi dan pengembangan game di samping untuk bersenang-senang. Saya merasa sangat nyaman untuk hanya memutar utas untuk setiap objek tunggal dan membiarkannya melakukan hal itu sendiri daripada memproses masing-masing melalui loop. Jika kode Anda tidak terganggu oleh perilaku non-deterministik dan Anda tidak memiliki tabrakan, itu bisa membuat pengkodean lebih mudah. Dengan kekuatan yang tersedia bagi kita sekarang, jika saya ingin kembali ke dalamnya, saya dapat dengan mudah membayangkan memintal beberapa ribu benang karena memiliki kekuatan pemrosesan dan memori yang cukup untuk menangani banyak objek diskrit!

Brian Knoblauch
sumber
1

Contoh sederhana untuk Erlang, yang dirancang untuk komunikasi: mentransfer paket jaringan. Ketika Anda melakukan satu permintaan http, Anda mungkin memiliki ribuan paket TCP / IP. Tambahkan ke ini bahwa semua orang terhubung pada saat yang sama, dan Anda memiliki kasus penggunaan Anda.

Pertimbangkan banyak aplikasi yang digunakan secara internal oleh perusahaan besar mana pun untuk menangani pesanan mereka atau apa pun yang mereka butuhkan. Server web bukan satu-satunya yang membutuhkan utas.

Florian Margaine
sumber
-2

Beberapa tugas rendering muncul di sini. Jika Anda melakukan rantai panjang ops pada setiap piksel gambar, dan jika ops itu dapat diparalelkan, maka bahkan gambar 1024x768 yang relatif kecil akan masuk ke braket "ratusan ribu".

Maximus Minimus
sumber
2
Beberapa tahun yang lalu, saya menghabiskan beberapa tahun melakukan pemrosesan gambar FLIR real-time, menghasilkan 256x256 gambar dengan 30 frame per detik. Kecuali jika Anda memiliki BANYAK prosesor HARDWARE, dan cara SEAMLESS untuk mempartisi data Anda di antara mereka, hal TERAKHIR yang ingin Anda lakukan adalah menambahkan pengalihan konteks, pertikaian memori, dan cache meronta-ronta ke biaya komputasi yang sebenarnya.
John R. Strohm
Itu tergantung pada pekerjaan yang dilakukan. Jika semua yang Anda lakukan adalah menyerahkan pekerjaan ke inti perangkat keras / unit eksekusi, setelah itu Anda dapat secara efektif melupakannya (dan perhatikan bahwa ini adalah cara kerja GPU sehingga ini bukan skenario hipotetis) maka pendekatannya adalah sah.
Maximus Minimus