Multithreading Dengan Jumlah Thread Yang Sangat Banyak

Saya sedang mengerjakan simulasi jaringan mesh dengan sejumlah besar node. Node meneruskan data antara node master yang berbeda di seluruh jaringan.

Masing-masing master hidup sekali dalam satu detik untuk menerima informasi, tetapi node budak tidak tahu kapan master aktif atau tidak, jadi ketika mereka memiliki informasi untuk dikirim, mereka mencoba melakukannya setiap 5 ms selama 1 detik untuk memastikan mereka dapat menemukan masternya.

Menjalankan ini di komputer biasa dengan 1600 node menghasilkan 1600 thread dan kinerjanya sangat buruk.

Apa pendekatan yang baik untuk menangani threading sehingga setiap node bertindak seolah-olah berjalan di threadnya sendiri?

Jika itu penting, saya membuat simulasi dengan python 2.7, tapi saya terbuka untuk mengubah ke sesuatu yang lain jika itu masuk akal.


person Liron    schedule 30.09.2013    source sumber
comment
Anda harus mempertimbangkan untuk menerapkan semacam antrian (utas-) atau setidaknya operator untuk mengelola aliran informasi. Namun sulit untuk mengatakannya tanpa mengetahui apa yang ingin Anda capai.   -  person tamasgal    schedule 30.09.2013
comment
Menjalankan 1600 thread tentu saja akan menghasilkan kinerja buruk pada komputer biasa. Anda mungkin perlu mempertimbangkan komputer berperforma tinggi, atau Anda dapat mencoba memanfaatkan GPU Anda untuk daya komputasi yang lebih besar. GPU bagus untuk multithreading.   -  person justhalf    schedule 30.09.2013
comment
@justhalf Tentu saja akan berdampak buruk. Setiap thread hanya aktif selama beberapa milidetik setiap detiknya dan tidak aktif sepanjang waktu, jadi menurut saya masalahnya bukan pada sumber daya CPU, melainkan pada jumlah inti atau hanya keberadaan thread sebanyak itu dan konteksnya yang mengalihkannya. memerlukan. Daripada 1.600, saya malah bilang 10.000. Saya mencari solusi yang baik untuk memperkirakan node-node ini berjalan secara paralel untuk memaksimalkan jumlah node yang dapat saya jalankan. Saya rasa pindah ke GPU tidak akan terlalu membantu di sini.   -  person Liron    schedule 30.09.2013
comment
Apa yang Anda maksud dengan memperkirakan node ini?   -  person justhalf    schedule 30.09.2013
comment
Mendekati karakteristik paralel penuhnya. Berjalan pada CPU biasa membuat saya tidak bisa memberikan threadnya sendiri pada setiap node dan berasumsi semuanya akan bekerja bergandengan tangan. Misalnya, saya dapat memiliki satu (atau beberapa) thread kontrol, yang memulai thread yang lebih kecil tepat ketika salah satu node memiliki informasi untuk dikirim, namun sering kali tidak ada thread untuk setiap node.   -  person Liron    schedule 30.09.2013
comment
Silakan baca di GlobalInterpreterLock.   -  person Lasse V. Karlsen    schedule 30.09.2013
comment
@LasseV.Karlsen - Saya berasumsi bahwa bahkan menggunakan Jython yang mengaktifkan banyak node pada CPU tidak akan membantu saya jika jumlah threadnya 10K atau 100K. Mungkin diperlukan arsitektur (dan/atau bahasa implementasi) yang berbeda di sini.   -  person Liron    schedule 30.09.2013


Jawaban (4)


Pertama, apakah Anda benar-benar menggunakan thread Python default biasa yang tersedia di interpreter default Python 2.7 (CPython), dan apakah semua kode Anda menggunakan Python? Jika demikian, Anda mungkin tidak benar-benar menggunakan beberapa inti CPU karena kunci penerjemah global yang dimiliki CPython (lihat https://wiki.python.org/moin/GlobalInterpreterLock). Anda mungkin dapat mencoba menjalankan kode Anda di bawah Jython, hanya untuk memeriksa apakah kinerjanya akan lebih baik.

Anda mungkin harus memikirkan kembali arsitektur aplikasi Anda dan beralih ke menjadwalkan acara secara manual daripada menggunakan thread, atau mungkin mencoba menggunakan sesuatu seperti greenlets (https://stackoverflow.com/a/15596277/1488821), tapi itu mungkin berarti pengaturan waktunya kurang tepat karena kurangnya paralelisme.

person Ivan Voras    schedule 30.09.2013
comment
Saya menggunakan python yang disertakan dengan Canopy (dipikirkan). Saya berasumsi itu adalah CPython biasa. - person Liron; 30.09.2013
comment
Dari sedikit googling sepertinya memang begitu. Namun seperti yang disarankan orang lain, masalah Anda sebaiknya diselesaikan dengan menggunakan arsitektur aplikasi yang berbeda. - person Ivan Voras; 01.10.2013
comment
Saya mengganti arsitekturnya untuk menggunakan gevents, dengan setiap node berjalan pada greenletnya sendiri. Untuk aplikasi saya, ini sebenarnya bekerja dengan sangat baik, karena saya tidak memerlukan fungsionalitas paralel yang sebenarnya, dan konkurensi sudah cukup. (Pada dasarnya greenlet Master hanya menetapkan tanda ketika Master secara aktif menerima koneksi, dan Slave menanyakan nilai tersebut pada Master secara langsung.) Terima kasih atas idenya. - person Liron; 01.10.2013

Bagi saya, 1600 thread terdengar banyak tetapi tidak berlebihan mengingat ini hanyalah simulasi. Jika ini adalah aplikasi produksi, mungkin ini tidak layak produksi.

Mesin standar seharusnya tidak mengalami kesulitan menangani 1600 thread. Mengenai OS artikel ini dapat memberi Anda dengan beberapa wawasan.

Jika menyangkut kode Anda, skrip Python bukanlah aplikasi asli tetapi skrip yang ditafsirkan dan oleh karena itu akan memerlukan lebih banyak sumber daya CPU untuk dijalankan.

Saya sarankan Anda mencoba menerapkan simulasi dalam C atau C++ yang akan menghasilkan aplikasi asli yang akan dijalankan lebih efisien.

person Olof Forshell    schedule 30.09.2013
comment
C# mungkin layak untuk dilihat juga. Ia melakukan thread dengan benar (tidak seperti Python) dan tidak terlalu mengejutkan bagi mereka yang terbiasa dengan kenyamanan Python; C/C++ mungkin terbukti terlalu sederhana untuk kenyamanan. - person bazza; 30.09.2013

Jangan gunakan threading untuk itu. Jika tetap menggunakan Python, biarkan node melakukan tindakannya satu per satu. Jika kinerja yang Anda lakukan baik-baik saja, Anda tidak perlu menggunakan C/C++. Jika tindakan yang dilakukan setiap node sederhana, hal itu mungkin berhasil. Lagi pula, tidak ada alasan untuk menggunakan thread di Python sama sekali. Utas Python sebagian besar dapat digunakan untuk membuat pemblokiran I/O agar tidak memblokir program Anda, bukan untuk penggunaan beberapa kernel CPU.

Jika Anda ingin benar-benar menggunakan pemrosesan paralel dan menulis node Anda seolah-olah mereka benar-benar terpisah dan bertukar hanya menggunakan pesan, Anda dapat menggunakan Erlang (http://www.erlang.org/). Ini adalah bahasa fungsional yang sangat cocok untuk menjalankan proses paralel dan membuat mereka bertukar pesan. Proses Erlang tidak dipetakan ke thread OS, dan Anda dapat membuat ribuan thread. Namun, Erlang adalah bahasa yang sepenuhnya berfungsi dan mungkin tampak sangat aneh jika Anda belum pernah menggunakan bahasa tersebut. Dan ini juga tidak terlalu cepat, jadi, seperti Python, ia tidak mungkin menangani 1600 tindakan setiap 5 md kecuali tindakannya cukup sederhana.

Terakhir, jika Anda tidak mendapatkan performa yang diinginkan menggunakan Python atau Erlang, Anda dapat beralih ke C atau C++. Namun tetap tidak menggunakan 1600 thread. Faktanya, penggunaan thread untuk mendapatkan kinerja hanya masuk akal jika jumlah thread tidak melebihi jumlah kernel CPU. Pola reaktor (dengan beberapa rangkaian reaktor) adalah yang mungkin Anda perlukan dalam kasus tersebut (http://en.wikipedia.org/wiki/Reactor_pattern). Ada implementasi yang sangat baik dari pola reaktor di perpustakaan boost.asio. Dijelaskan di sini: http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio/

person Ellioh    schedule 30.09.2013
comment
Tujuan saya di sini bukan untuk meningkatkan throughput dengan banyak thread, tetapi untuk mensimulasikan komunikasi antar-node. Hanya ada sedikit pemrosesan pada setiap node. Saya akan melihat erlang dan melihat tampilannya. - person Liron; 30.09.2013

Beberapa pemikiran acak di sini:

Saya melakukannya dengan cukup baik dengan beberapa ratus thread yang bekerja seperti ini di Java; itu bisa dilakukan dengan bahasa yang tepat. (Tapi saya belum mencobanya dengan Python.)

Dalam bahasa apa pun, Anda dapat menjalankan kode simpul utama dalam satu thread; biarkan saja berulang terus menerus, jalankan kode untuk setiap master di setiap siklus. Namun, Anda akan kehilangan manfaat dari banyak inti. Di sisi lain, Anda juga akan kehilangan masalah multithreading. (Anda dapat memiliki, katakanlah, 4 thread seperti itu, memanfaatkan inti tetapi membuat sakit kepala multithreading kembali. Ini juga akan menjaga overhead thread tetap rendah, tetapi kemudian ada pemblokiran...)

Satu masalah besar yang saya alami adalah thread saling memblokir. Mengaktifkan 100 thread untuk memanggil metode yang sama pada objek yang sama pada waktu yang sama tanpa menunggu satu sama lain memerlukan sedikit pemikiran dan bahkan penelitian. Saya menemukan program multithreading saya pada awalnya sering hanya menggunakan 25% dari CPU 4-inti bahkan ketika kehabisan tenaga. Ini mungkin salah satu alasan mengapa Anda berjalan lambat.

Jangan biarkan node budak Anda mengulangi pengiriman data. Node master harus menjadi hidup sebagai respons terhadap data yang masuk, atau mempunyai cara untuk menyimpannya hingga menjadi hidup, atau suatu kombinasi.

Memang bermanfaat untuk memiliki lebih banyak thread daripada core. Setelah Anda memiliki dua thread, mereka dapat saling memblokir (dan akan memblokirnya jika mereka berbagi data). Jika Anda memiliki kode untuk dijalankan yang tidak dapat diblokir, Anda ingin menjalankannya di threadnya sendiri sehingga kode tersebut tidak akan menunggu kode yang memblokir untuk membuka blokir dan menyelesaikannya. Saya menemukan begitu saya memiliki beberapa thread, mereka mulai berkembang biak dengan gila-gilaan--karena itulah program ratusan thread saya. Bahkan ketika 100 thread diblokir di satu tempat meskipun saya sangat cemerlang, masih banyak thread lain yang membuat inti tetap sibuk!

person RalphChapin    schedule 30.09.2013