Bagaimana saya bisa menangani peristiwa KeyboardInterrupt dengan Pools multi-pemrosesan python? Ini adalah contoh sederhana:
from multiprocessing import Pool
from time import sleep
from sys import exit
def slowly_square(i):
sleep(1)
return i*i
def go():
pool = Pool(8)
try:
results = pool.map(slowly_square, range(40))
except KeyboardInterrupt:
# **** THIS PART NEVER EXECUTES. ****
pool.terminate()
print "You cancelled the program!"
sys.exit(1)
print "\nFinally, here are the results: ", results
if __name__ == "__main__":
go()
Ketika menjalankan kode di atas, KeyboardInterrupt
akan dinaikkan ketika saya menekan ^C
, tetapi proses hanya hang pada saat itu dan saya harus membunuhnya secara eksternal.
Saya ingin dapat menekan ^C
kapan saja dan menyebabkan semua proses keluar dengan anggun.
python
multiprocessing
pool
keyboardinterrupt
Fragsworth
sumber
sumber
Jawaban:
Ini adalah bug Python. Saat menunggu kondisi dalam threading.Condition.wait (), KeyboardInterrupt tidak pernah dikirim. Repro:
Pengecualian KeyboardInterrupt tidak akan dikirim sampai wait () kembali, dan itu tidak pernah kembali, sehingga interupsi tidak pernah terjadi. KeyboardInterrupt hampir pasti mengganggu kondisi menunggu.
Perhatikan bahwa ini tidak terjadi jika batas waktu ditentukan; cond.wait (1) akan menerima interupsi segera. Jadi, solusinya adalah menentukan batas waktu. Untuk melakukannya, ganti
dengan
atau serupa.
sumber
Dari apa yang saya temukan baru-baru ini, solusi terbaik adalah mengatur proses pekerja untuk mengabaikan SIGINT sama sekali, dan membatasi semua kode pembersihan ke proses induk. Ini memperbaiki masalah untuk proses pekerja yang menganggur dan sibuk, dan tidak memerlukan kode penanganan kesalahan dalam proses anak Anda.
Penjelasan dan contoh kode lengkap dapat ditemukan di http://noswap.com/blog/python-multiprocessing-keyboardinterrupt/ dan http://github.com/jreese/multiprocessing-keyboardinterrupt masing-masing.
sumber
time.sleep(10)
dalam proses utama. Jika Anda menghapus tidur itu, atau jika Anda menunggu sampai proses mencoba untuk bergabung di kolam, yang harus Anda lakukan untuk menjamin pekerjaan selesai, maka Anda masih menderita masalah yang sama yang merupakan proses utama tidak dapat menerima KeyboardInterrupt ketika sedang menunggu padajoin
operasi pemungutan suara .pool.terminate()
tidak pernah dieksekusi. Membuat anak-anak mengabaikan sinyal tidak menghasilkan apa-apa. @ Jawaban Glenn memecahkan masalah..join()
kecuali pada interupsi - itu hanya secara manual memeriksa hasil.apply_async()
menggunakanAsyncResult.ready()
untuk melihat apakah sudah siap, yang berarti kita sudah selesai.Untuk beberapa alasan, hanya pengecualian yang diwarisi dari
Exception
kelas dasar yang ditangani secara normal. Sebagai solusinya, Anda dapat menaikkan kembaliKeyboardInterrupt
sebagaiException
contoh:Biasanya Anda akan mendapatkan output berikut:
Jadi, jika Anda menekan
^C
, Anda akan mendapatkan:sumber
KeyboardInterrupt
tiba saatmultiprocessing
sedang melakukan pertukaran data IPC sendiri makatry..catch
tidak akan diaktifkan (jelas).raise KeyboardInterruptError
denganreturn
. Anda hanya perlu memastikan bahwa proses anak berakhir segera setelah KeyboardInterrupt diterima. Nilai kembali tampaknya diabaikan,main
masih KeyboardInterrupt diterima.Biasanya struktur sederhana ini berfungsi untuk Ctrl- Cdi Pool:
Sebagaimana dinyatakan dalam beberapa posting serupa:
Abadikan keyboardinterrupt dalam Python tanpa coba-kecuali
sumber
Jawaban yang dipilih tidak menangani masalah inti tetapi efek samping yang serupa.
Jesse Noller, penulis perpustakaan multiprosesing, menjelaskan cara menangani CTRL + C dengan benar saat menggunakan
multiprocessing.Pool
dalam posting blog lama .sumber
os.setpgrp()
dari dalam masa depanProcessPoolExecutor
tidak mendukung fungsi penginisialisasi. Di Unix, Anda dapat memanfaatkanfork
strategi dengan menonaktifkan sighandler pada proses utama sebelum membuat Pool dan mengaktifkannya kembali sesudahnya. Dalam kerikil , saya membungkamSIGINT
proses anak secara default. Saya tidak mengetahui alasan mereka tidak melakukan hal yang sama dengan Pools Python. Pada akhirnya, pengguna dapat mengatur ulangSIGINT
pawang jika dia ingin melukai dirinya sendiri.Tampaknya ada dua masalah yang membuat pengecualian sementara multi-proses mengganggu. Yang pertama (dicatat oleh Glenn) adalah bahwa Anda perlu menggunakan
map_async
dengan batas waktu alih-alihmap
untuk mendapatkan tanggapan langsung (yaitu, jangan selesai memproses seluruh daftar). Yang kedua (dicatat oleh Andrey) adalah bahwa multiprocessing tidak menangkap pengecualian yang tidak diwarisi dariException
(misalnya,SystemExit
). Jadi, inilah solusi saya yang menangani keduanya:sumber
function
ini cukup berumur panjang (ratusan detik).map
dan semuanya baik-baik saja.@Linux Cli Aik
memberikan solusi di bawah ini yang menghasilkan perilaku ini. Penggunaanmap_async
tidak selalu diinginkan jika utas utama bergantung pada hasil dari proses anak.Saya menemukan, untuk saat ini, solusi terbaik adalah tidak menggunakan fitur multiprocessing.pool melainkan memutar fungsi pool Anda sendiri. Saya memberikan contoh yang menunjukkan kesalahan dengan apply_async serta contoh yang menunjukkan bagaimana cara menghindari penggunaan fungsi kumpulan sama sekali.
http://www.bryceboe.com/2010/08/26/python-multiprocessing-and-keyboardinterrupt/
sumber
Saya seorang pemula di Python. Saya mencari jawaban di mana-mana dan menemukan ini dan beberapa blog dan video youtube lainnya. Saya telah mencoba untuk menyalin tempel kode penulis di atas dan mereproduksinya di python 2.7.13 saya di windows 7 64-bit. Ini dekat dengan apa yang ingin saya capai.
Saya membuat proses anak saya untuk mengabaikan ControlC dan membuat proses induk berakhir. Sepertinya melewati proses anak tidak menghindari masalah ini untuk saya.
Bagian yang dimulai pada
pool.terminate()
sepertinya tidak pernah dieksekusi.sumber
map_async
ke pengguna, yang saya khususnya tidak suka. Dalam banyak situasi, seperti punyaku, utas utama perlu menunggu proses masing-masing selesai. Ini adalah salah satu alasan mengapamap
ada!Anda dapat mencoba menggunakan metode apply_async dari objek Pool, seperti ini:
Keluaran:
Keuntungan dari metode ini adalah bahwa hasil yang diproses sebelum gangguan akan dikembalikan dalam kamus hasil:
sumber
Anehnya sepertinya Anda harus menangani
KeyboardInterrupt
anak-anak juga. Saya berharap ini berfungsi seperti yang tertulis ... coba ubahslowly_square
ke:Itu seharusnya bekerja seperti yang Anda harapkan.
sumber