Saya sedang menulis aplikasi GUI yang secara teratur mengambil data melalui koneksi web. Karena pengambilan ini membutuhkan waktu beberapa saat, ini menyebabkan UI menjadi tidak responsif selama proses pengambilan (tidak dapat dibagi menjadi beberapa bagian yang lebih kecil). Inilah mengapa saya ingin melakukan outsourcing koneksi web ke utas pekerja terpisah.
[Ya, saya tahu, sekarang saya punya dua masalah .]
Bagaimanapun, aplikasinya menggunakan PyQt4, jadi saya ingin tahu pilihan apa yang lebih baik: Gunakan utas Qt atau gunakan threading
modul Python ? Apa kelebihan / kekurangan masing-masing? Atau apakah Anda memiliki saran yang sama sekali berbeda?
Edit (re bounty): Sementara solusi dalam kasus khusus saya mungkin akan menggunakan permintaan jaringan non-pemblokiran seperti yang disarankan Jeff Ober dan Lukáš Lalinský (jadi pada dasarnya menyerahkan masalah konkurensi ke implementasi jaringan), saya masih ingin yang lainnya jawaban mendalam untuk pertanyaan umum:
Apa keuntungan dan kerugian menggunakan thread PyQt4 (yaitu Qt) dibandingkan thread asli Python (dari threading
modul)?
Edit 2: Terima kasih atas jawaban Anda. Meskipun tidak ada kesepakatan 100%, tampaknya ada konsensus luas bahwa jawabannya adalah "gunakan Qt", karena keuntungannya adalah integrasi dengan seluruh pustaka, sementara tidak menyebabkan kerugian nyata.
Bagi siapapun yang ingin memilih di antara dua implementasi threading, saya sangat menyarankan mereka membaca semua jawaban yang disediakan di sini, termasuk utas milis PyQt yang ditautkan oleh abbot .
Ada beberapa jawaban yang saya pertimbangkan untuk hadiah itu; pada akhirnya saya memilih kepala biara untuk referensi eksternal yang sangat relevan; itu, bagaimanapun, panggilan dekat.
Terima kasih lagi.
sumber
QCoreApplication.postEvent
dari utas Python dengan kecepatan 100 kali per detik, dalam aplikasi yang berjalan lintas platform dan telah diuji selama 1000 jam. Saya tidak pernah melihat ada masalah dari itu. Saya pikir tidak apa-apa selama objek tujuan terletak di MainThread atau QThread. Saya juga membungkusnya di perpustakaan yang bagus, lihat qtutils .Utas Python akan lebih sederhana dan lebih aman, dan karena ini untuk aplikasi berbasis I / O, mereka dapat melewati GIL. Yang mengatakan, apakah Anda telah mempertimbangkan non-blocking I / O menggunakan Twisted atau non-blocking sockets / select?
EDIT: lebih lanjut tentang utas
Benang Python
Utas Python adalah utas sistem. Namun, Python menggunakan kunci interpreter global (GIL) untuk memastikan bahwa interpreter hanya mengeksekusi blok ukuran tertentu dari instruksi kode byte pada satu waktu. Untungnya, Python merilis GIL selama operasi input / output, membuat utas berguna untuk mensimulasikan I / O non-pemblokiran.
Peringatan penting: Ini bisa menyesatkan, karena jumlah instruksi kode byte tidak sesuai dengan jumlah baris dalam program. Bahkan satu tugas mungkin tidak atomic dengan Python, jadi kunci mutex diperlukan untuk setiap blok kode yang harus dieksekusi secara atomik, bahkan dengan GIL.
Benang QT
Saat Python menyerahkan kontrol ke modul yang dikompilasi pihak ketiga, GIL akan dirilis. Ini menjadi tanggung jawab modul untuk memastikan atomicity jika diperlukan. Saat kontrol dikembalikan, Python akan menggunakan GIL. Ini dapat membuat penggunaan pustaka pihak ketiga dalam hubungannya dengan utas membingungkan. Bahkan lebih sulit lagi untuk menggunakan library threading eksternal karena menambahkan ketidakpastian tentang di mana dan kapan kontrol berada di tangan modul vs interpreter.
Benang QT beroperasi dengan GIL dirilis. Benang QT dapat mengeksekusi kode pustaka QT (dan kode modul terkompilasi lainnya yang tidak memperoleh GIL) secara bersamaan. Namun, kode Python yang dieksekusi dalam konteks utas QT masih memperoleh GIL, dan sekarang Anda harus mengelola dua set logika untuk mengunci kode Anda.
Pada akhirnya, baik utas QT dan utas Python adalah pembungkus di sekitar utas sistem. Utas Python sedikit lebih aman untuk digunakan, karena bagian-bagian yang tidak ditulis dengan Python (secara implisit menggunakan GIL) menggunakan GIL dalam kasus apa pun (meskipun peringatan di atas masih berlaku.)
I / O non-pemblokiran
Untaian menambah kerumitan luar biasa pada aplikasi Anda. Terutama ketika berhadapan dengan interaksi yang sudah kompleks antara interpreter Python dan kode modul yang dikompilasi. Meskipun banyak yang menganggap pemrograman berbasis peristiwa sulit untuk diikuti, I / O non-pemblokiran berbasis peristiwa seringkali jauh lebih sulit untuk dipikirkan daripada utas.
Dengan asynchronous I / O, Anda selalu bisa yakin bahwa, untuk setiap deskriptor terbuka, jalur eksekusi konsisten dan teratur. Jelas ada, masalah yang harus diatasi, seperti apa yang harus dilakukan ketika kode bergantung pada satu saluran terbuka lebih jauh tergantung pada hasil kode yang akan dipanggil ketika saluran terbuka lainnya mengembalikan data.
Satu solusi bagus untuk I / O berbasis acara dan non-pemblokiran adalah pustaka Diesel baru . Itu terbatas pada Linux saat ini, tetapi sangat cepat dan cukup elegan.
Ini juga sepadan dengan waktu Anda untuk mempelajari pyevent , pembungkus di sekitar perpustakaan libevent yang luar biasa, yang menyediakan kerangka kerja dasar untuk pemrograman berbasis acara menggunakan metode tercepat yang tersedia untuk sistem Anda (ditentukan pada waktu kompilasi).
sumber
Keuntungannya
QThread
adalah terintegrasi dengan pustaka Qt lainnya. Artinya, metode berbasis thread di Qt perlu mengetahui di thread mana mereka menjalankan, dan untuk memindahkan objek antar thread, Anda perlu menggunakannyaQThread
. Fitur berguna lainnya adalah menjalankan event loop Anda sendiri dalam sebuah thread.Jika Anda mengakses server HTTP, Anda harus mempertimbangkan
QNetworkAccessManager
.sumber
QNetworkAccessManager
tampak menjanjikan. Terima kasih.Saya bertanya pada diri sendiri pertanyaan yang sama ketika saya bekerja di PyTalk .
Jika Anda menggunakan Qt, Anda harus menggunakannya
QThread
untuk dapat menggunakan kerangka kerja Qt dan terutama sistem sinyal / slot.Dengan mesin sinyal / slot, Anda akan dapat berbicara dari utas ke utas lainnya dan dengan setiap bagian dari proyek Anda.
Selain itu, tidak ada pertanyaan performa tentang pilihan ini karena keduanya adalah pengikatan C ++.
Inilah pengalaman saya tentang PyQt dan utas.
Saya mendorong Anda untuk menggunakan
QThread
.sumber
Jeff memiliki beberapa poin bagus. Hanya satu utas utama yang dapat melakukan pembaruan GUI. Jika Anda memang perlu memperbarui GUI dari dalam utas, sinyal koneksi antrian Qt-4 memudahkan pengiriman data melintasi utas dan secara otomatis akan dipanggil jika Anda menggunakan QThread; Saya tidak yakin apakah mereka akan melakukannya jika Anda menggunakan utas Python, meskipun mudah untuk menambahkan parameter ke
connect()
.sumber
Saya juga tidak bisa merekomendasikan, tetapi saya dapat mencoba menjelaskan perbedaan antara utas CPython dan Qt.
Pertama-tama, utas CPython tidak berjalan secara bersamaan, setidaknya bukan kode Python. Ya, mereka membuat utas sistem untuk setiap utas Python, namun hanya utas yang saat ini memegang Kunci Penerjemah Global yang diizinkan untuk berjalan (ekstensi C dan kode FFI mungkin melewatinya, tetapi bytecode Python tidak dijalankan sementara utas tidak memegang GIL).
Di sisi lain, kami memiliki utas Qt, yang pada dasarnya merupakan lapisan umum di atas utas sistem, tidak memiliki Kunci Penerjemah Global, dan dengan demikian mampu berjalan secara bersamaan. Saya tidak yakin bagaimana PyQt mengatasinya, namun kecuali utas Qt Anda memanggil kode Python, mereka harus dapat berjalan secara bersamaan (bar berbagai kunci tambahan yang mungkin diterapkan dalam berbagai struktur).
Untuk penyempurnaan ekstra, Anda dapat memodifikasi jumlah instruksi bytecode yang ditafsirkan sebelum mengalihkan kepemilikan GIL - nilai yang lebih rendah berarti lebih banyak pengalihan konteks (dan mungkin daya tanggap yang lebih tinggi) tetapi kinerja yang lebih rendah per utas individu (pengalih konteks memiliki biayanya - jika Anda coba ganti setiap beberapa instruksi itu tidak membantu kecepatan.)
Semoga membantu dengan masalah Anda :)
sumber
Saya tidak dapat mengomentari perbedaan persis antara utas Python dan PyQt, tetapi saya telah melakukan apa yang Anda coba gunakan
QThread
,QNetworkAcessManager
dan memastikan untuk memanggilQApplication.processEvents()
saat utas masih hidup. Jika daya tanggap GUI benar-benar masalah yang Anda coba selesaikan, nanti akan membantu.sumber
QNetworkAcessManager
tidak membutuhkan utas atauprocessEvents
. Ini menggunakan operasi IO asynchronous.QNetworkAcessManager
danhttplib2
. Kode async saya menggunakanhttplib2
.