배경 :QThreadPool - 중단하는 방법/어떻게 현명하게 사용하는 waitForDone 방법
나는 내가 (내가 할 수있는 개인 편집기에서 오는 API를 통해 PostgreSQL 데이터베이스에 공간 쿼리를 만들 수있는 스크립트가 데이터베이스에 직접 쿼리하지 마십시오.) 이 API는 파이썬 3.2에서 작동합니다. 요약하면이 스크립트는 원하는 지리학 적 공간에서이 데이터베이스의 요소를 다운로드하는 데 사용됩니다. 영역에 따라 1에서 100 가지 이상의 요소를 얻을 수 있습니다. 각 요소의 크기는 매우 다릅니다 (Ko에서 Go까지).
주 창을 사용하면 모든 옵션을 설정 한 다음 전역 프로세스를 시작할 수 있습니다. 실행되면 콘솔 창이 나타나서 현재 진행중인 작업을 볼 수 있습니다. 항목이 다운로드되면 짧은 "보고서"가 콘솔에 표시됩니다. 현재 모든 것은 한 번에 하나의 요소로 순차적으로 이루어집니다. 상상할 수 있듯이이 요소가 상당히 크면 다운로드 프로세스가 끝날 때까지 기다리는 동안 콘솔이 멈 춥니 다.
코드 :
즉 사용자 잠금 방지 (내가 여기에 전체 스크립트를 게시하지 않을거야,하지만 아주 간단한 스크립트를 통해 내가 해결하기 위해 노력하고있어 큰 문제를 보여주기 위해 노력할 것입니다 인터페이스/무슨 일이 일어나고 있는지에 대한 실시간 출력물을 가지고 있습니다.)
그래서 이러한 결빙 문제를 피하기 위해 스레드를 사용하는 것이 나에게 가장 좋은 솔루션 인 것처럼 보였습니다. 다운로드 프로세스를 시뮬레이션하기 위해 (이전 장 참조) url.request urlretrieve 메소드를 여러 URL (크기가 다른 파일을 가리킴)과 함께 사용했습니다.
import os
import sys
import time
import urllib.request
from PyQt4 import QtCore, QtGui
url_1m = 'http://ipv4.sbg.proof.ovh.net/files/1Mio.dat'
url_10m = 'http://ipv4.sbg.proof.ovh.net/files/10Mio.dat'
url_100m = 'http://ipv4.sbg.proof.ovh.net/files/100Mio.dat'
url_1g = 'http://ipv4.sbg.proof.ovh.net/files/1Gio.dat'
url_10g = 'http://ipv4.sbg.proof.ovh.net/files/10Gio.dat'
urls = (url_1m, url_10m, url_100m, url_1g, url_10g)
# ---------------------------------------------------------------------------------
class DownloadWorkerSignals(QtCore.QObject):
"""
Defines the signals available from a running download worker thread.
"""
finished = QtCore.pyqtSignal(str)
# ---------------------------------------------------------------------------------
class DownloadWorker(QtCore.QRunnable):
"""
Worker thread
"""
def __init__(self, url, filepath, filename, index):
super(DownloadWorker, self).__init__()
self.url = url
self.file_path = filepath
self.filename = filename
self.index = index
self.signals = DownloadWorkerSignals()
@QtCore.pyqtSlot(str)
def run(self):
t = time.time()
message = 'Thread %d started\n' % self.index
try:
# The urlretrieve method will copy a network object to a local file
urllib.request.urlretrieve(url=self.url,
filename=os.path.join(self.file_path,
self.filename))
except IOError as error:
message += str(error) + '\n'
finally:
message += 'Thread %d ended %.2f s\n' % (self.index, time.time() - t)
self.signals.finished.emit(message) # Done
# ---------------------------------------------------------------------------------
class Main(QtGui.QMainWindow):
"""
Main window
"""
def __init__(self):
super(self.__class__, self).__init__()
self.resize(400, 200)
self.setWindowTitle("Main")
self.setWindowModality(QtCore.Qt.ApplicationModal)
self.centralwidget = QtGui.QWidget(self)
self.setCentralWidget(self.centralwidget)
# Ok/Close
# -------------------------------------------------------------------------
self.buttonBox = QtGui.QDialogButtonBox(self.centralwidget)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel |
QtGui.QDialogButtonBox.Ok)
self.buttonBox.setGeometry(QtCore.QRect(10, 160, 380, 20))
# Connect definition
# -------------------------------------------------------------------------
self.connect(self.buttonBox,
QtCore.SIGNAL('accepted()'),
self.button_ok_clicked)
self.connect(self.buttonBox,
QtCore.SIGNAL('rejected()'),
self.button_cancel_clicked)
# Connect functions
# -----------------------------------------------------------------------------
def button_cancel_clicked(self):
self.close()
def button_ok_clicked(self):
# Launch console
console = Console(parent=self)
console.exec_()
# ---------------------------------------------------------------------------------------------------------------
class Console(QtGui.QDialog):
"""
Console window
"""
def __init__(self, parent):
super(self.__class__, self).__init__()
self.parent = parent
self.resize(400, 200)
self.setWindowTitle("Console")
self.setModal(True)
self.verticalLayout = QtGui.QVBoxLayout(self)
# Text edit
# -------------------------------------------------------------------------
self.text_edit = QtGui.QPlainTextEdit(self)
self.text_edit.setReadOnly(True)
self.text_edit_cursor = QtGui.QTextCursor(self.text_edit.document())
self.verticalLayout.addWidget(self.text_edit)
# Ok/Close
# -------------------------------------------------------------------------
self.button_box = QtGui.QDialogButtonBox(self)
self.button_box.setStandardButtons(QtGui.QDialogButtonBox.Close)
self.verticalLayout.addWidget(self.button_box)
# Connect definition
# -------------------------------------------------------------------------
self.connect(self.button_box.button(QtGui.QDialogButtonBox.Close),
QtCore.SIGNAL('clicked()'),
self.button_cancel_clicked)
# Post initialization
# -------------------------------------------------------------------------
self.threadpool = QtCore.QThreadPool()
self.threadpool.setMaxThreadCount(2)
for index, url in enumerate(urls):
worker = DownloadWorker(url=url,
filepath='C:\\Users\\philippe\\Downloads',
filename='url_%d.txt' % index,
index=index)
worker.signals.finished.connect(self.write_message)
self.threadpool.start(worker)
'''
I have to wait for the end of the thread pool to make a post-processing.
If I use the waitForDone I don't see my console until the all work is done
'''
# self.threadpool.waitForDone()
# self.write_stram('Thread pool finished')
# Connect functions
# -----------------------------------------------------------------------------
def button_cancel_clicked(self):
if self.threadpool.activeThreadCount() != 0:
pass # How to interrupt the threadpool ?
self.close()
@QtCore.pyqtSlot(str)
def write_message(self, text):
self.text_edit.insertPlainText(text)
cursor = self.text_edit.textCursor()
self.text_edit.setTextCursor(cursor)
# ---------------------------------------------------------------------------------
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = Main()
window.show()
app.exec_()
질문 :
모든 것이 예상대로 작동하는 것 같다하지만이 문제가 발생 : 좀 후 처리을해야 스레드 풀 프로세스가 끝나면
- 을 . waitForDone 메서드를 사용하면 모든 작업이 완료 될 때까지 내 콘솔이 표시되지 않고 동작 유형이 아닙니다. 싶었습니다.
- 콘솔의 취소 버튼을 클릭하면 스레드 풀 을 인터럽트해야하며이를 관리하는 방법을 알지 못합니다.
2 번 질문에 대한 답변을 찾았습니다. –