Saya sangat baru dengan Python dan pemrograman multithread secara umum. Pada dasarnya, saya memiliki skrip yang akan menyalin file ke lokasi lain. Saya ingin ini ditempatkan di utas lain sehingga saya dapat menampilkan ....
bahwa skrip masih berjalan.
Masalah yang saya alami adalah jika file tidak dapat disalin maka akan menimbulkan pengecualian. Ini ok jika berjalan di utas utama; namun, memiliki kode berikut tidak berfungsi:
try:
threadClass = TheThread(param1, param2, etc.)
threadClass.start() ##### **Exception takes place here**
except:
print "Caught an exception"
Di kelas utas itu sendiri, saya mencoba melemparkan kembali pengecualian, tetapi tidak berhasil. Saya telah melihat orang-orang di sini mengajukan pertanyaan serupa, tetapi mereka semua tampaknya melakukan sesuatu yang lebih spesifik daripada apa yang saya coba lakukan (dan saya tidak begitu mengerti solusi yang ditawarkan). Saya telah melihat orang menyebutkan penggunaan sys.exc_info()
, namun saya tidak tahu di mana atau bagaimana menggunakannya.
Semua bantuan sangat dihargai!
EDIT: Kode untuk kelas utas di bawah:
class TheThread(threading.Thread):
def __init__(self, sourceFolder, destFolder):
threading.Thread.__init__(self)
self.sourceFolder = sourceFolder
self.destFolder = destFolder
def run(self):
try:
shul.copytree(self.sourceFolder, self.destFolder)
except:
raise
TheThread
? Contoh kode mungkin?Jawaban:
Masalahnya adalah
thread_obj.start()
segera kembali. Utas anak yang Anda buat dijalankan dalam konteksnya sendiri, dengan tumpukannya sendiri. Setiap pengecualian yang terjadi ada dalam konteks utas anak, dan itu ada di tumpukannya sendiri. Salah satu cara yang dapat saya pikirkan saat ini untuk mengkomunikasikan informasi ini ke utas induk adalah dengan menggunakan semacam pesan yang lewat, sehingga Anda dapat melihatnya.Coba ini untuk ukuran:
sumber
multiprocessing
setara: gist.github.com/2311116bucket.get()
kenaikanQueue.Empty
? Maka utasjoin(0.1)
akan selesai danisAlive() is False
, dan Anda melewatkan pengecualian Anda.Queue
tidak perlu dalam kasus sederhana ini - Anda bisa menyimpan info pengecualian sebagai propertiExcThread
selama Anda memastikan bahwarun()
melengkapi tepat setelah pengecualian (yang dilakukan dalam contoh sederhana ini). Maka Anda cukup mengajukan kembali pengecualian setelah (atau selama)t.join()
. Tidak ada masalah sinkronisasi karenajoin()
memastikan utas telah selesai. Lihat jawaban oleh Rok Strniša di bawah stackoverflow.com/a/12223550/126362The
concurrent.futures
Modul memudahkan untuk melakukan pekerjaan di thread terpisah (atau proses) dan menangani pengecualian yang dihasilkan:concurrent.futures
disertakan dengan Python 3.2, dan tersedia sebagai modul backportedfutures
untuk versi sebelumnya.sumber
concurrent.futures.as_completed
, Anda dapat segera diberi tahu karena pengecualian muncul: stackoverflow.com/questions/2829329/…Ada banyak jawaban rumit yang sangat aneh untuk pertanyaan ini. Apakah saya terlalu menyederhanakan ini, karena ini tampaknya cukup untuk sebagian besar hal bagi saya.
Jika Anda yakin Anda hanya akan menjalankan satu atau versi lain dari Python, Anda bisa mengurangi
run()
metode menjadi hanya versi yang rusak (jika Anda hanya akan berjalan pada versi Python sebelum 3), atau hanya versi bersih (jika Anda hanya akan menjalankan versi Python dimulai dengan 3).Contoh penggunaan:
Dan Anda akan melihat pengecualian yang muncul di utas lainnya saat Anda bergabung.
Jika Anda menggunakan
six
atau hanya pada Python 3, Anda bisa meningkatkan informasi jejak tumpukan yang Anda dapatkan ketika pengecualian kembali. Alih-alih hanya tumpukan di titik gabungan, Anda bisa membungkus pengecualian dalam dengan pengecualian luar baru, dan mendapatkan kedua jejak tumpukan denganatau
sumber
Meskipun tidak mungkin untuk secara langsung menangkap pengecualian yang dilemparkan ke utas yang berbeda, berikut adalah kode untuk mendapatkan sesuatu yang sangat dekat dengan fungsi ini secara transparan. Utas anak Anda harus subkelas
ExThread
kelas alih-alihthreading.Thread
dan utas induk harus memanggilchild_thread.join_with_exception()
metode alih-alihchild_thread.join()
saat menunggu utas menyelesaikan tugasnya.Detail teknis dari implementasi ini: ketika utas anak melempar pengecualian, ia diteruskan ke induk melalui
Queue
dan dilemparkan lagi di utas induk. Perhatikan bahwa tidak ada kesibukan menunggu dalam pendekatan ini.sumber
BaseException
, bukanException
? Yang Anda lakukan hanyalah menyebarkan pengecualian dari satuThread
ke yang lain. Saat ini, IE, aKeyboardInterrupt
, akan diabaikan secara diam-diam jika diangkat di utas latar belakang.join_with_exception
hang tanpa batas waktu jika dipanggil untuk kedua kalinya pada utas mati. Perbaiki: github.com/fraserharris/threading-extensions/blob/master/…Queue
itu tidak perlu; lihat komentar saya untuk jawaban @ Santa. Anda dapat menyederhanakannya menjadi sesuatu seperti jawaban Rok Strniša di bawah stackoverflow.com/a/12223550/126362Jika pengecualian terjadi di utas, cara terbaik adalah menaikkannya di utas penelepon selama
join
. Anda bisa mendapatkan informasi tentang pengecualian yang sedang ditangani menggunakansys.exc_info()
fungsi ini. Informasi ini dapat dengan mudah disimpan sebagai properti dari objek thread sampaijoin
dipanggil, pada titik mana ia dapat diangkat kembali.Perhatikan bahwa
Queue.Queue
(seperti yang disarankan dalam jawaban lain) tidak diperlukan dalam kasus sederhana ini di mana utas melemparkan paling banyak 1 pengecualian dan selesai tepat setelah melemparkan pengecualian . Kami menghindari kondisi balapan dengan hanya menunggu utas selesai.Misalnya, tambah
ExcThread
(di bawah),excRun
ganti (bukanrun
).Python 2.x:
Python 3.x:
Bentuk argumen 3 untuk
raise
hilang dalam Python 3, jadi ubah baris terakhir ke:sumber
concurrent.futures.as_completed
https://docs.python.org/3.7/library/concurrent.futures.html#concurrent.futures.as_completed
Solusi berikut:
Queue
Sumber:
Output yang mungkin:
Sayangnya tidak mungkin untuk membunuh berjangka untuk membatalkan yang lain karena salah satu gagal:
concurrent.features
; Python: concurrent.futures Bagaimana cara membatalkannya?threading
: Apakah ada cara untuk membunuh Thread?Jika Anda melakukan sesuatu seperti:
kemudian
with
menangkapnya, dan menunggu utas kedua selesai sebelum melanjutkan. Berikut ini berperilaku serupa:karena
future.result()
kembali memunculkan pengecualian jika terjadi.Jika Anda ingin keluar dari seluruh proses Python, Anda mungkin lolos
os._exit(0)
, tetapi ini berarti Anda membutuhkan refactor.Kelas khusus dengan semantik pengecualian sempurna
Saya akhirnya coding antarmuka yang sempurna untuk diri saya sendiri di: Cara yang tepat untuk membatasi jumlah maksimum utas berjalan sekaligus? bagian "Contoh antrian dengan penanganan kesalahan". Kelas itu bertujuan untuk nyaman, dan memberi Anda kontrol total atas pengiriman dan penanganan hasil / kesalahan.
Diuji pada Python 3.6.7, Ubuntu 18.04.
sumber
Ini adalah masalah kecil yang tidak menyenangkan, dan saya ingin memasukkan solusi saya. Beberapa solusi lain yang saya temukan (async.io misalnya) terlihat menjanjikan tetapi juga memberikan sedikit kotak hitam. Pendekatan loop antrian / acara mengaitkan Anda dengan implementasi tertentu. Namun, kode sumber berjangka berjangka hanya sekitar 1000 baris, dan mudah dipahami . Itu memungkinkan saya untuk dengan mudah menyelesaikan masalah saya: membuat utas pekerja ad-hoc tanpa banyak pengaturan, dan untuk dapat menangkap pengecualian di utas utama.
Solusi saya menggunakan API berjangka bersamaan dan API threading. Ini memungkinkan Anda untuk membuat pekerja yang memberi Anda utas dan masa depan. Dengan begitu, Anda dapat bergabung dengan utas untuk menunggu hasilnya:
... atau Anda dapat membiarkan pekerja hanya mengirim panggilan balik ketika selesai:
... atau Anda dapat mengulang sampai acara selesai:
Berikut kodenya:
... dan fungsi tes:
sumber
Sebagai noobie untuk Threading, saya butuh waktu lama untuk memahami bagaimana menerapkan kode Mateusz Kobos (di atas). Berikut adalah versi yang diklarifikasi untuk membantu memahami cara menggunakannya.
sumber
Cara yang sama seperti RickardSjogren's tanpa Antrian, sys dll. Tetapi juga tanpa beberapa pendengar sinyal: mengeksekusi langsung pengecualian handler yang sesuai dengan blok kecuali.
Hanya self._callback dan kecuali blok yang sedang dijalankan () yang ditambahkan ke threading normal.
sumber
Saya tahu saya agak terlambat ke pesta di sini, tetapi saya memiliki masalah yang sangat mirip tetapi itu termasuk menggunakan tkinter sebagai GUI, dan mainloop membuatnya tidak mungkin untuk menggunakan solusi yang bergantung pada .join (). Karena itu saya mengadaptasi solusi yang diberikan dalam EDIT dari pertanyaan awal, tetapi membuatnya lebih umum untuk membuatnya lebih mudah dipahami orang lain.
Inilah kelas utas baru yang sedang beraksi:
Tentu saja Anda selalu dapat membuatnya menangani pengecualian dengan cara lain dari pencatatan, seperti mencetaknya, atau mengeluarkannya ke konsol.
Ini memungkinkan Anda untuk menggunakan kelas ExceptionThread persis seperti yang Anda lakukan pada kelas Thread, tanpa modifikasi khusus.
sumber
Salah satu metode yang saya sukai didasarkan pada pola pengamat . Saya mendefinisikan kelas sinyal yang menggunakan utas saya untuk memancarkan pengecualian untuk pendengar. Itu juga dapat digunakan untuk mengembalikan nilai dari utas. Contoh:
Saya tidak memiliki cukup pengalaman bekerja dengan utas untuk mengklaim bahwa ini adalah metode yang sepenuhnya aman. Tapi itu berhasil bagi saya dan saya suka fleksibilitasnya.
sumber
Menggunakan pengecualian telanjang bukanlah praktik yang baik karena Anda biasanya menangkap lebih banyak daripada yang Anda tawar-menawar.
Saya sarankan memodifikasi
except
HANYA untuk pengecualian yang ingin Anda tangani. Saya tidak berpikir bahwa meningkatkannya memiliki efek yang diinginkan, karena ketika Anda pergi ke instantiateTheThread
di bagian luartry
, jika itu menimbulkan pengecualian, tugas itu tidak akan pernah terjadi.Alih-alih, Anda mungkin ingin hanya mengingatkan dan melanjutkan, seperti:
Lalu ketika pengecualian itu tertangkap, Anda bisa menanganinya di sana. Kemudian ketika bagian luar
try
menangkap pengecualianTheThread
, Anda tahu itu bukan yang sudah Anda tangani, dan akan membantu Anda mengisolasi aliran proses Anda.sumber
Cara sederhana menangkap pengecualian utas dan berkomunikasi kembali ke metode pemanggil bisa dengan melewati kamus atau daftar ke
worker
metode.Contoh (meneruskan kamus ke metode pekerja):
sumber
Bungkus Utas dengan penyimpanan pengecualian.
sumber
pygolang menyediakan sync.WorkGroup yang, khususnya, menyebarkan pengecualian dari utas pekerja yang bertelur ke utas utama. Sebagai contoh:
memberikan yang berikut saat dijalankan:
Kode asli dari pertanyaan adalah:
sumber