- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
创建多处理/GUI 编码系统的最佳方法是什么?
我想为互联网社区创建一个地方,让他们可以找到有关如何使用 multiprocessing
的示例。 python中的模块。
我看过几个multiprocessing
的小例子在互联网上处理在主模块中调用的简单全局函数,但我发现这很少能轻易转化为任何人在 GUI 方面实际所做的任何事情。我认为许多程序会有他们想在单独的进程中使用的函数作为对象的方法(可能是其他对象的集合等),也许单个 GUI 元素会有一个关联的对象需要调用它流程等
例如,我有一个相对复杂的程序,并且在为其获取响应式 GUI 时遇到问题,我认为这是由于我对 multiprocessing
缺乏理解所致。和线程 QThread
.但是,我确实知道下面给出的示例至少会以我希望的方式在进程之间传递信息(由于能够执行 print
语句),但我的 GUI 仍处于锁定状态。有谁知道这可能是什么原因造成的,如果我对多线程/多处理架构缺乏了解,这是否仍然是一个问题?
这是我正在做的一个小伪代码示例:
class Worker:
...
def processing(self, queue):
# put stuff into queue in a loop
# This thread gets data from Worker
class Worker_thread(QThread):
def __init__(self):
...
# make process with Worker inside
def start_processing(self):
# continuously get data from Worker
# send data to Tab object with signals/slots
class Tab(QTabWidget):
# spawn a thread separate from main GUI thread
# update GUI using slot
def update_GUI()
这段代码是完全可编译的示例,它体现了我程序的上层结构:
from PyQt4 import QtCore, QtGui
import multiprocessing as mp
import numpy as np
import sys
import time
# This object can hold several properties which will be used for the processing
# and will be run in the background, while it updates a thread with all of it's progress
class Worker:
def __init__(self, some_var):
self.some_var = some_var
self.iteration = 0
def some_complex_processing(self, queue):
for i in range(0,5000):
self.iteration += 1
queue.put(self.iteration)
queue.put('done with processing')
# This Woker_thread is a thread which will spawn a separate process (Worker).
# This separate is needed in order to separate the data retrieval
# from the main GUI thread, which should only quickly update when needed
class Worker_thread(QtCore.QThread):
# signals and slots are used to communicate back to the main GUI thread
update_signal = QtCore.pyqtSignal(int)
done_signal = QtCore.pyqtSignal()
def __init__(self, parent, worker):
QtCore.QThread.__init__(self, parent)
self.queue = mp.Queue()
self.worker = worker
self.parent = parent
self.process = mp.Process(target=self.worker.some_complex_processing, args=(self.queue,))
# When the process button is pressed, this function will start getting data from Worker
# this data is then retrieved by the queue and pushed through a signal
# to Tab.update_GUI
@QtCore.pyqtSlot()
def start_computation(self):
self.process.start()
while(True):
try:
message = self.queue.get()
self.update_signal.emit(message)
except EOFError:
pass
if message == 'done with processing':
self.done_signal.emit()
break
#self.parent.update_GUI(message)
self.process.join()
return
# Each tab will start it's own thread, which will spawn a process
class Tab(QtGui.QTabWidget):
start_comp = QtCore.pyqtSignal()
def __init__(self, parent, this_worker):
self.parent = parent
self.this_worker = this_worker
QtGui.QTabWidget.__init__(self, parent)
self.treeWidget = QtGui.QTreeWidget(self)
self.properties = QtGui.QTreeWidgetItem(self.treeWidget, ["Properties"])
self.step = QtGui.QTreeWidgetItem(self.properties, ["Iteration #"])
self.thread = Worker_thread(parent=self, worker=self.this_worker)
self.thread.update_signal.connect(self.update_GUI)
self.thread.done_signal.connect(self.thread.quit)
self.start_comp.connect(self.thread.start_computation)
self.thread.start()
###############################
# Here is what should update the GUI at every iteration of Worker.some_complex_processing()
# The message appears to be getting sent, due to seeing the print statement in the console, but the GUI is not updated.
@QtCore.pyqtSlot(int)
def update_GUI(self, iteration):
self.step.setText(0, str(iteration))
#time.sleep(0.1)
print iteration
def start_signal_emit(self):
self.start_comp.emit()
# GUI stuff
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent = None):
QtGui.QMainWindow.__init__(self)
self.tab_list = []
self.setTabShape(QtGui.QTabWidget.Rounded)
self.centralwidget = QtGui.QWidget(self)
self.top_level_layout = QtGui.QGridLayout(self.centralwidget)
self.tabWidget = QtGui.QTabWidget(self.centralwidget)
self.top_level_layout.addWidget(self.tabWidget, 1, 0, 25, 25)
process_button = QtGui.QPushButton("Process")
self.top_level_layout.addWidget(process_button, 0, 1)
QtCore.QObject.connect(process_button, QtCore.SIGNAL("clicked()"), self.process)
self.setCentralWidget(self.centralwidget)
self.centralwidget.setLayout(self.top_level_layout)
# Make Tabs in loop from button
for i in range(0,10):
name = 'tab' + str(i)
self.tab_list.append(Tab(self.tabWidget, Worker(name)))
self.tabWidget.addTab(self.tab_list[-1], name)
# Do the processing
def process(self):
for tab in self.tab_list:
tab.start_signal_emit()
return
if __name__ == "__main__":
app = QtGui.QApplication([])
win = MainWindow()
win.show()
sys.exit(app.exec_())
更多信息:我正在编写一个程序,我想从中生成多个进程,并让它们在整个处理过程中不断显示它们的进度。我希望该程序能够进行多进程处理,以便尽可能地从程序中获得最佳速度。
目前,我正在尝试使用线程来生成进程并使用信号和槽来更新 GUI,同时队列不断检索数据。看来 queues
, signals
, 和 slots
使用 print
时工作语句,但不能更新 GUI。如果有人对我应该如何构建它以使程序更易于管理有任何其他建议,我想学习。
编辑:我已经对 Min Lin 提出的调整进行了调整,并添加了 Worker
一个QObject
这样moveToThread()
会工作。
这是我目前的新代码:
from PyQt4 import QtCore, QtGui
import multiprocessing as mp
import numpy as np
import sys
import time
class Worker(QtCore.QObject):
update_signal = QtCore.pyqtSignal(int)
done_signal = QtCore.pyqtSignal()
def __init__(self, some_var):
QtCore.QObject.__init__(self, parent=None)
self.some_var = some_var
self.iteration = 0
self.queue = mp.Queue()
self.process = mp.Process(target=self.some_complex_processing, args=(self.queue,))
def some_complex_processing(self, queue):
for i in range(0,5000):
self.iteration += 1
queue.put(self.iteration)
queue.put('done with processing')
@QtCore.pyqtSlot()
def start_computation(self):
self.process.start()
while(True):
try:
message = self.queue.get()
self.update_signal.emit(message)
except EOFError:
pass
if message == 'done with processing':
self.done_signal.emit()
break
self.process.join()
return
class Tab(QtGui.QTabWidget):
start_comp = QtCore.pyqtSignal()
def __init__(self, parent, this_worker):
self.parent = parent
self.this_worker = this_worker
QtGui.QTabWidget.__init__(self, parent)
self.treeWidget = QtGui.QTreeWidget(self)
self.properties = QtGui.QTreeWidgetItem(self.treeWidget, ["Properties"])
self.step = QtGui.QTreeWidgetItem(self.properties, ["Iteration #"])
# Use QThread is enough
self.thread = QtCore.QThread();
# Change the thread affinity of worker to self.thread.
self.this_worker.moveToThread(self.thread);
self.this_worker.update_signal.connect(self.update_GUI)
self.this_worker.done_signal.connect(self.thread.quit)
self.start_comp.connect(self.this_worker.start_computation)
self.thread.start()
###############################
# Here is what should update the GUI at every iteration of Worker.some_complex_processing()
# The message appears to be getting sent, due to seeing the print statement in the console, but the GUI is not updated.
@QtCore.pyqtSlot(int)
def update_GUI(self, iteration):
self.step.setText(0, str(iteration))
#time.sleep(0.1)
print iteration
def start_signal_emit(self):
self.start_comp.emit()
# GUI stuff
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent = None):
QtGui.QMainWindow.__init__(self)
self.tab_list = []
self.setTabShape(QtGui.QTabWidget.Rounded)
self.centralwidget = QtGui.QWidget(self)
self.top_level_layout = QtGui.QGridLayout(self.centralwidget)
self.tabWidget = QtGui.QTabWidget(self.centralwidget)
self.top_level_layout.addWidget(self.tabWidget, 1, 0, 25, 25)
process_button = QtGui.QPushButton("Process")
self.top_level_layout.addWidget(process_button, 0, 1)
QtCore.QObject.connect(process_button, QtCore.SIGNAL("clicked()"), self.process)
self.setCentralWidget(self.centralwidget)
self.centralwidget.setLayout(self.top_level_layout)
# Make Tabs in loop from button
for i in range(0,10):
name = 'tab' + str(i)
self.tab_list.append(Tab(self.tabWidget, Worker(name)))
self.tabWidget.addTab(self.tab_list[-1], name)
# Do the processing
def process(self):
for tab in self.tab_list:
tab.start_signal_emit()
return
if __name__ == "__main__":
app = QtGui.QApplication([])
win = MainWindow()
win.show()
sys.exit(app.exec_())
感谢您提供的所有答案,我很欣赏每个人在描述他们认为是解决方案的想法时所做的详细程度,但不幸的是,我还无法执行这些类型的流程在 GUI 上显示对象的属性时,它们所属的对象。
然而,我从这篇文章中学到了很多东西,这让我意识到我目前拥有的线程版本正在挂起 GUI,因为 GUI 更新功能太大并且需要太多处理。
所以,我选择了QTimer()
接近我的多线程版本,它的性能要好得多!我会建议任何面临类似问题的人至少尝试类似的事情。
我不知道这种解决 GUI 更新问题的方法,现在它是对我面临的问题的伪或临时修复。
最佳答案
GUI 应用程序非常适合测试东西,因为它很容易产生新任务并可视化正在发生的事情,所以我写了一个小示例应用程序(Screenshot,代码在下面)因为我确实想学习它为了我自己。
起初,我采用了与您类似的方法,尝试实现消费者/生产者模式,我在后台进程中苦苦挣扎,不断循环等待新工作,并为自己来回沟通。然后我发现了 Pool界面,然后我可以用几行代码替换所有那些丑陋的代码。您只需要一个池和一些回调:
#!/usr/bin/env python3
import multiprocessing, time, random, sys
from PySide.QtCore import * # equivalent: from PyQt4.QtCore import *
from PySide.QtGui import * # equivalent: from PyQt4.QtGui import *
def compute(num):
print("worker() started at %d" % num)
random_number = random.randint(1, 6)
if random_number in (2, 4, 6):
raise Exception('Random Exception in _%d' % num)
time.sleep(random_number)
return num
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.toolBar = self.addToolBar("Toolbar")
self.toolBar.addAction(QAction('Add Task', self, triggered=self.addTask))
self.list = QListWidget()
self.setCentralWidget(self.list)
# Pool of Background Processes
self.pool = multiprocessing.Pool(processes=4)
def addTask(self):
num_row = self.list.count()
self.pool.apply_async(func=compute, args=(num_row,), callback=self.receiveResult,
error_callback=self.receiveException)
item = QListWidgetItem("item %d" % num_row)
item.setForeground(Qt.gray)
self.list.addItem(item)
def receiveResult(self, result):
assert isinstance(result, int)
print("end_work(), where result is %s" % result)
self.list.item(result).setForeground(Qt.darkGreen)
def receiveException(self, exception):
error = str(exception)
_pos = error.find('_') + 1
num_row = int(error[_pos:])
item = self.list.item(num_row)
item.setForeground(Qt.darkRed)
item.setText(item.text() + ' Retry...')
self.pool.apply_async(func=compute, args=(num_row,), callback=self.receiveResult,
error_callback=self.receiveException)
if __name__ == '__main__':
app = QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
sys.exit(app.exec_())
编辑:我做了另一个使用 QTimer 而不是回调的示例,定期检查队列中的条目,更新 QProgressBar:
#!/usr/bin/env python3
import multiprocessing, multiprocessing.pool, time, random, sys
from PySide.QtCore import *
from PySide.QtGui import *
def compute(num_row):
print("worker started at %d" % num_row)
random_number = random.randint(1, 10)
for second in range(random_number):
progress = float(second) / float(random_number) * 100
compute.queue.put((num_row, progress,))
time.sleep(1)
compute.queue.put((num_row, 100))
def pool_init(queue):
# see http://stackoverflow.com/a/3843313/852994
compute.queue = queue
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.toolBar = self.addToolBar("Toolbar")
self.toolBar.addAction(QAction('Add Task', self, triggered=self.addTask))
self.table = QTableWidget()
self.table.verticalHeader().hide()
self.table.setColumnCount(2)
self.setCentralWidget(self.table)
# Pool of Background Processes
self.queue = multiprocessing.Queue()
self.pool = multiprocessing.Pool(processes=4, initializer=pool_init, initargs=(self.queue,))
# Check for progress periodically
self.timer = QTimer()
self.timer.timeout.connect(self.updateProgress)
self.timer.start(2000)
def addTask(self):
num_row = self.table.rowCount()
self.pool.apply_async(func=compute, args=(num_row,))
label = QLabel("Queued")
bar = QProgressBar()
bar.setValue(0)
self.table.setRowCount(num_row + 1)
self.table.setCellWidget(num_row, 0, label)
self.table.setCellWidget(num_row, 1, bar)
def updateProgress(self):
if self.queue.empty(): return
num_row, progress = self.queue.get() # unpack
print("received progress of %s at %s" % (progress, num_row))
label = self.table.cellWidget(num_row, 0)
bar = self.table.cellWidget(num_row, 1)
bar.setValue(progress)
if progress == 100:
label.setText('Finished')
elif label.text() == 'Queued':
label.setText('Downloading')
self.updateProgress() # recursion
if __name__ == '__main__':
app = QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
sys.exit(app.exec_())
关于python - 用于对抗 "Not Responding"阻塞的多处理 GUI 模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15698251/
如果我有一个像盒子一样的 div,我用 10% 的不透明度让它变得非常性感。我该如何应对它,因为 div 中的所有内容也都具有不透明度。假设我有一个带有 1px 边框和文本的框 (div),在其上设置
我知道 AngularJS 会运行某些代码两次,有时甚至更多,例如 $watch 事件,不断检查模型状态等。 但是我的代码: function MyController($scope, User, l
目前,我们在对我们的 cassandra 数据库使用 apache spark 时挑战我们的架构,因为我们遇到了非常糟糕的读取性能。 spark & cassandra 发生的硬件是一个云服务器,16
所以最近我遇到了以下问题:我必须创建一个处理请求的服务器,以便在主进程使用这些值时更新某些值。 所以这里,服务器处理函数是在子进程中,我想停止的时候都无法停止。 为了测试在 threading.Thr
准备好的语句不允许参数化表名。为了确保无法插入任何代码,我想使用 ctype_alnum 来验证进入数据库模块的所有表名(删除下划线后),以保护应用程序免受其他部分错误的影响。 function in
经典算法书籍(TAOCP、CLR)(以及不太经典的书籍,例如 fxtbook)充满了命令式 算法。这对于实现严重基于数组的算法最为明显,例如组合生成(算法中同时使用数组索引和数组值)或联合查找算法。
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
这个问题已经有答案了: Apply a Greasemonkey/Tampermonkey userscript to an iframe (6 个回答) 已关闭 5 年前。 我想知道是否可以让 Gr
SELECT p.id FROM produkty p, przyporzadkowania pr, stany_magazynowe, gk_grupy_produkty INNER JOIN su
我想将 Azure ACS 添加到我的一个站点,但所有功能都出现问题。我有一个 MVC 应用程序,它使用全局过滤器为请求的生命周期设置自定义 IPrincipal。 WIF 的“添加 STS 引用”方
我想将 Azure ACS 添加到我的一个站点,但所有功能都出现问题。我有一个 MVC 应用程序,它使用全局过滤器为请求的生命周期设置自定义 IPrincipal。 WIF 的“添加 STS 引用”方
Google 的 YouTube Analytics API 仅基于 Oauth2。我正在使用以下测试脚本来查看是否可以获得访问权限: import os import google.oauth2.c
随着 Visual Studio 2008 的发布,Microsoft 为 JavaScript 实现了代码完成和 IntelliSense 支持。 不幸的是,对 JavaScript 的支持充其量是
我在准备语句方面有更多经验,我知道它们非常适合抵御 SQL 注入(inject)攻击。 我想知道 pl/pgsql 的 format/USING 和 quote_literal/quote_nulla
我是一名优秀的程序员,十分优秀!