Saya mencoba memahami threading dengan Python. Saya telah melihat dokumentasi dan contoh-contohnya, tetapi sejujurnya, banyak contoh yang terlalu canggih dan saya kesulitan memahaminya.
Bagaimana Anda dengan jelas menunjukkan tugas yang dibagi untuk multi-threading?
Jawaban:
Sejak pertanyaan ini diajukan pada tahun 2010, telah ada penyederhanaan nyata dalam bagaimana melakukan multithreading sederhana dengan Python dengan peta dan kumpulan .
Kode di bawah ini berasal dari artikel / posting blog yang harus Anda periksa (tidak ada afiliasi) - Paralelisme dalam satu baris: Model yang Lebih Baik untuk Tugas Sehari-Hari Threading . Saya akan meringkas di bawah ini - akhirnya hanya menjadi beberapa baris kode:
Yang merupakan versi multithreaded dari:
Deskripsi
Penerapan
multiprocessing.dummy
persis sama dengan modul multiprosesing, tetapi menggunakan utas sebagai gantinya ( perbedaan penting - gunakan beberapa proses untuk tugas-tugas yang intensif CPU; utas untuk (dan selama) I / O ):Dan hasil waktu:
Melewati banyak argumen (hanya berfungsi seperti ini di Python 3.3 dan yang lebih baru ):
Untuk melewati beberapa larik:
Atau untuk melewatkan konstanta dan array:
Jika Anda menggunakan versi Python yang lebih lama, Anda bisa meneruskan beberapa argumen melalui solusi ini ).
(Terima kasih kepada pengguna136036 untuk komentar bermanfaat.)
sumber
with Pool(8) as p: p.map( *whatever* )
dan menyingkirkan garis pembukuan juga.Berikut ini contoh sederhana: Anda perlu mencoba beberapa URL alternatif dan mengembalikan konten yang pertama merespons.
Ini adalah kasus di mana threading digunakan sebagai optimisasi sederhana: setiap subthread sedang menunggu URL untuk menyelesaikan dan merespons, untuk menempatkan kontennya pada antrian; setiap utas adalah daemon (tidak akan mempertahankan proses jika utas utama berakhir - itu lebih umum daripada tidak); utas utama memulai semua subthreads, melakukan
get
antrian untuk menunggu sampai salah satu dari mereka melakukan aput
, kemudian memancarkan hasil dan mengakhiri (yang mencatat semua subthreads yang mungkin masih berjalan, karena mereka adalah daemon threads).Penggunaan utas yang benar dalam Python selalu terhubung ke operasi I / O (karena CPython tidak menggunakan banyak inti untuk menjalankan tugas yang terikat CPU, satu-satunya alasan untuk threading adalah tidak memblokir proses sementara ada menunggu beberapa I / O ). Antrian hampir selalu merupakan cara terbaik untuk membuat pekerjaan keluar dari utas ke thread dan / atau mengumpulkan hasil pekerjaan, dan, pada dasarnya, mereka secara intrinsik aman, sehingga mereka menyelamatkan Anda dari kekhawatiran tentang kunci, kondisi, peristiwa, semaphore, dan inter Konsep koordinasi / komunikasi.
sumber
join()
metode ini, karena itu akan membuat utas utama menunggu sampai selesai tanpa memakan prosesor dengan terus-menerus memeriksa nilainya. @Alex: terima kasih, inilah yang saya butuhkan untuk memahami cara menggunakan utas.Queue
nama modul denganqueue
. Nama metode sama.s = q.get()
print s
@ krs013 Anda tidak memerlukannyajoin
karena Queue.get () sedang memblokir.CATATAN : Untuk paralelisasi aktual dalam Python, Anda harus menggunakan multiprosesor modul untuk memotong beberapa proses yang dieksekusi secara paralel (karena kunci juru bahasa global, benang Python menyediakan interleaving, tetapi sebenarnya dieksekusi secara seri, bukan paralel, dan hanya berguna saat interleaving operasi I / O).
Namun, jika Anda hanya mencari interleaving (atau sedang melakukan operasi I / O yang dapat diparalelkan meskipun ada kunci juru bahasa global), maka modul threading adalah tempat untuk memulai. Sebagai contoh yang sangat sederhana, mari kita pertimbangkan masalah menjumlahkan rentang besar dengan menjumlahkan subrang secara paralel:
Perhatikan bahwa di atas adalah contoh yang sangat bodoh, karena sama sekali tidak ada I / O dan akan dieksekusi secara serial meskipun diselingi (dengan tambahan overhead konteks switching) di CPython karena kunci juru bahasa global.
sumber
thread1
berjalan sampai selesai sementara utas utama blok, maka hal yang sama terjadi denganthread2
, maka utas utama melanjutkan dan mencetak nilai-nilai yang mereka kumpulkan.super(SummingThread, self).__init__()
? Seperti dalam stackoverflow.com/a/2197625/806988Seperti yang lain disebutkan, CPython dapat menggunakan utas hanya untuk I / O menunggu karena GIL .
Jika Anda ingin mendapat manfaat dari banyak inti untuk tugas yang terikat CPU, gunakan multiprosesor :
sumber
f
berfungsi. Secara paralel, program utama sekarang hanya menunggu proses untuk keluar,join
mengikuti itu. Jika bagian utama baru saja keluar, subproses mungkin atau mungkin tidak berjalan sampai selesai, sehingga melakukanjoin
selalu dianjurkan.map
fungsi ada di sini: stackoverflow.com/a/28463266/2327328Hanya sebuah catatan: Antrian tidak diperlukan untuk threading.
Ini adalah contoh paling sederhana yang dapat saya bayangkan yang menunjukkan 10 proses berjalan secara bersamaan.
sumber
for
loop kedua , Anda dapat memanggilthread.start()
loop pertama.Jawaban dari Alex Martelli membantu saya. Namun, ini adalah versi modifikasi yang saya pikir lebih bermanfaat (setidaknya bagi saya).
Diperbarui: berfungsi di Python 2 dan Python 3
sumber
import Queue ModuleNotFoundError: No module named 'Queue'
Saya menjalankan python 3.6.5 beberapa posting menyebutkan bahwa dalam python 3.6.5 itu adalahqueue
tetapi bahkan setelah saya mengubahnya, masih tidak berfungsiDiberi fungsi
f
,, utas seperti ini:Untuk meneruskan argumen
f
sumber
Thread
objek membersihkan. Lihat dokumen . Adais_alive()
metode yang dapat Anda gunakan untuk memeriksa utas jika perlu.is_alive
metodenya, tetapi saya tidak tahu bagaimana menerapkannya pada utas. Saya mencoba menugaskanthread1=threading.Thread(target=f).start()
dan kemudian memeriksanyathread1.is_alive()
, tetapithread1
diisi denganNone
, jadi tidak berhasil di sana. Apakah Anda tahu jika ada cara lain untuk mengakses utas?thread1=threading.Thread(target=f)
diikuti olehthread1.start()
. Maka Anda bisa melakukannyathread1.is_alive()
.thread1.is_alive()
pengembalianFalse
segera setelah fungsi keluar.Saya menemukan ini sangat berguna: buat sebanyak utas sebagai inti dan biarkan mereka menjalankan banyak tugas (dalam hal ini, memanggil program shell):
sumber
Python 3 memiliki fasilitas meluncurkan tugas paralel . Ini membuat pekerjaan kami lebih mudah.
Ini memiliki penyatuan benang dan proses penyatuan .
Berikut ini memberikan wawasan:
Contoh ThreadPoolExecutor ( sumber )
ProcessPoolExecutor ( sumber )
sumber
Menggunakan modul concurrent.futures baru yang terik
Pendekatan pelaksana mungkin tampak akrab bagi semua orang yang pernah mengotori Jawa sebelumnya.
Juga sebagai catatan: Untuk menjaga alam semesta tetap waras, jangan lupa untuk menutup kumpulan / pelaksana Anda jika Anda tidak menggunakan
with
konteks (yang sangat mengagumkan sehingga ia melakukannya untuk Anda)sumber
Bagi saya, contoh sempurna untuk threading adalah memantau peristiwa asinkron. Lihatlah kode ini.
Anda dapat bermain dengan kode ini dengan membuka sesi IPython dan melakukan sesuatu seperti:
Tunggu beberapa menit
sumber
Sebagian besar dokumentasi dan tutorial menggunakan Python
Threading
danQueue
modul, dan itu bisa membuat kewalahan bagi pemula.Mungkin mempertimbangkan
concurrent.futures.ThreadPoolExecutor
modul Python 3.Dikombinasikan dengan
with
klausa dan daftar pemahaman itu bisa menjadi pesona nyata.sumber
Saya melihat banyak contoh di sini di mana tidak ada pekerjaan nyata yang dilakukan, dan kebanyakan terikat CPU. Berikut adalah contoh tugas yang terikat CPU yang menghitung semua bilangan prima antara 10 juta dan 10,05 juta. Saya telah menggunakan keempat metode di sini:
Berikut adalah hasil pada mesin empat-core Mac OS X saya
sumber
if __name__ == '__main__':
sebelum panggilan utama, jika tidak menumbuhkan pengukuran itu sendiri dan cetakan Sebuah usaha telah dilakukan untuk memulai proses baru sebelum ... .Berikut adalah contoh impor CSV yang sangat sederhana menggunakan threading. (Penyertaan perpustakaan mungkin berbeda untuk tujuan yang berbeda.)
Fungsi Helper:
Fungsi Pengemudi:
sumber
Saya ingin berkontribusi dengan contoh sederhana dan penjelasan yang saya temukan berguna ketika saya harus mengatasi masalah ini sendiri.
Dalam jawaban ini Anda akan menemukan beberapa informasi tentang Python GIL (kunci juru bahasa global) dan contoh sederhana sehari-hari yang ditulis menggunakan multiprocessing.dummy plus beberapa tolok ukur sederhana.
Global Interpreter Lock (GIL)
Python tidak mengizinkan multi-threading dalam arti kata yang sebenarnya. Ini memiliki paket multi-threading, tetapi jika Anda ingin multi-thread untuk mempercepat kode Anda, maka biasanya bukan ide yang baik untuk menggunakannya.
Python memiliki konstruk yang disebut global interpreter lock (GIL). GIL memastikan bahwa hanya satu dari 'utas' Anda yang dapat dieksekusi pada satu waktu. Sebuah thread mendapatkan GIL, melakukan sedikit pekerjaan, lalu meneruskan GIL ke thread berikutnya.
Hal ini terjadi sangat cepat sehingga bagi mata manusia, sepertinya utas Anda berjalan paralel, tetapi mereka benar-benar hanya bergantian menggunakan inti CPU yang sama.
Semua operan GIL ini menambah biaya eksekusi. Ini berarti bahwa jika Anda ingin membuat kode Anda berjalan lebih cepat maka menggunakan paket threading sering bukan ide yang baik.
Ada alasan untuk menggunakan paket threading Python. Jika Anda ingin menjalankan beberapa hal secara bersamaan, dan efisiensi bukan masalah, maka itu benar-benar baik dan nyaman. Atau jika Anda menjalankan kode yang perlu menunggu sesuatu (seperti beberapa I / O) maka itu bisa masuk akal. Tetapi pustaka threading tidak akan membiarkan Anda menggunakan core CPU tambahan.
Multi-threading dapat dialihdayakan ke sistem operasi (dengan melakukan multi-pemrosesan), dan beberapa aplikasi eksternal yang memanggil kode Python Anda (misalnya, Spark atau Hadoop ), atau beberapa kode yang panggilan kode Python Anda (misalnya: Anda bisa minta kode Python Anda memanggil fungsi C yang melakukan hal-hal multi-threaded yang mahal).
Mengapa Ini Penting?
Karena banyak orang menghabiskan banyak waktu untuk mencari kemacetan dalam kode multi-threaded Python mewah mereka sebelum mereka mengetahui apa itu GIL.
Setelah informasi ini jelas, inilah kode saya:
sumber
Berikut adalah multi threading dengan contoh sederhana yang akan sangat membantu. Anda dapat menjalankannya dan memahami dengan mudah bagaimana multi threading bekerja di Python. Saya menggunakan kunci untuk mencegah akses ke utas lain sampai utas sebelumnya menyelesaikan pekerjaan mereka. Dengan menggunakan baris kode ini,
Anda dapat membiarkan sejumlah proses sekaligus dan tetap berpegang pada sisa utas yang akan berjalan nanti atau setelah proses sebelumnya selesai.
sumber
Dengan meminjam dari posting ini kita tahu tentang memilih antara multithreading, multiprocessing, dan async /
asyncio
dan penggunaannya.Python 3 memiliki perpustakaan bawaan baru untuk konkurensi dan paralelisme: concurrent.futures
Jadi saya akan menunjukkan melalui percobaan untuk menjalankan empat tugas (yaitu
.sleep()
metode) denganThreading-Pool
cara:Keluaran:
[ CATATAN ]:
multiprocessing
vsthreading
) Anda bisa mengubahThreadPoolExecutor
keProcessPoolExecutor
.sumber
Tidak ada solusi sebelumnya yang benar-benar menggunakan banyak core pada server GNU / Linux saya (di mana saya tidak memiliki hak administrator). Mereka hanya berlari pada satu inti.
Saya menggunakan
os.fork
antarmuka tingkat bawah untuk menelurkan banyak proses. Ini adalah kode yang berfungsi untuk saya:sumber
sumber