- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在编写一个 PySide2 应用程序,它将结果绘制到某个计算中,并尝试对计算进行多线程处理以避免锁定 GUI。我试图使用 QThreadPool 在与绘图相关的选项交互后,在一个单独的线程中运行计算,该线程通过信号将结果返回到回调方法,该方法使用 matplotlib 绘制结果。
问题是,当我连续太快(但不是太快)更改选项选择时,应用程序崩溃。如果移除线程,则不会发生这种情况。
我知道很多问题是由于绘图发生在工作线程而不是主线程中引起的,所以我相信我已经确保绘图仅发生在主线程中。
我想部分问题是我可能会误解使用信号和槽时运行的内容。我尝试查找代码中不同点使用的线程,但只能使用 QThread.currentThread(),它返回地址,但并没有真正帮助,因为 QThread.currentThreadId() 会导致此错误: AttributeError: type object “PySide2.QtCore.QThread”没有属性“currentThreadId”。
我尝试通过编写类似崩溃的应用程序的最小版本来隔离行为,其中大部分内容我已放在下面。我已经排除了计算,因为我不确定是否可以共享它,并且我已经用带有一些选项的 QListWidget 替换了绘图选项。与适当的应用程序相比,它需要更多的交互才能崩溃,在某些情况下,在一两秒内选择几个选项后就会崩溃,但希望能说明这一点。
class MainWindow(QObject):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.main_window = QMainWindow()
self.main_window.setCentralWidget(QWidget())
self.main_window.centralWidget().setLayout(QHBoxLayout())
self.setup_main_window()
def setup_main_window(self):
print(f'setup_main_window thread address: {QThread.currentThreadId()}')
self.load_list()
self.plot_figure = PlotFigure()
self.canvas = FigureCanvas(self.plot_figure)
self.plot_figure.plot(update=False)
self.main_window.centralWidget().layout().addWidget(self.canvas)
def load_list(self):
self.order_list = QListWidget(self.main_window)
self.list_items = [
QListWidgetItem('1', self.order_list),
QListWidgetItem('2', self.order_list),
QListWidgetItem('3', self.order_list),
QListWidgetItem('4', self.order_list),
]
self.order_list.itemClicked.connect(self.order_list_item_changed)
self.main_window.centralWidget().layout().addWidget(self.order_list)
def order_list_item_changed(self):
print(f'order_list_item_changed thread address: {QThread.currentThreadId()}')
self.plot_figure.plot()
def show(self):
if self.main_window is not None:
self.main_window.show()
class PlotFigure(Figure):
def __init__(self):
super().__init__()
def plot(self):
print(f'plot thread address: {QThread.currentThreadId()}')
print(f'update: {update}')
print(f'connecting signals')
worker = Worker(self.calc)
#worker.signals.close.connect(self.set_end_calc)
worker.signals.finished.connect(self.plot_result)
print(f'threads: {QThreadPool.globalInstance().activeThreadCount()}')
QThreadPool.globalInstance().start(worker)
def plot_result(self, m, xs, ys):
print(f'plot_result thread address: {QThread.currentThreadId()}')
print('plotting')
fig = self.canvas.figure
fig.clear()
self.axis = fig.add_subplot(111)
self.image = self.axis.imshow(m,
origin='lower',
aspect='auto',
cmap=matplotlib.cm.get_cmap('inferno'),
interpolation='bilinear',
extent=(xs[0], xs[-1], ys[0], ys[-1])
)
self.canvas.draw()
class WorkerSignals(QtCore.QObject):
close = QtCore.Signal(bool)
start = QtCore.Signal(bool)
finished = QtCore.Signal(list, list, list)
class Worker(QtCore.QRunnable):
def __init__(self, worker_method):
super(Worker, self).__init__()
self.signals = WorkerSignals()
self.worker_method = worker_method
def run(self):
self.signals.close.emit(True)
print('close signal sent')
m, xs, ys = self.worker_method()
print('calc done')
self.signals.finished.emit(m, xs, ys)
我应该能够选择新选项(在列表小部件周围单击),从线程池启动一个新线程,该线程运行计算并发送回要绘制的结果。当短时间内选择太多选项时,应用程序会崩溃。当所有事情都发生在主线程中时,这种情况就不会发生。
谁能告诉我应用程序可能崩溃的原因并提供修复崩溃的解决方案吗?
最佳答案
您所描述的崩溃行为表明多个线程试图同时操作相同的数据/变量。由于您没有限制可以启动的额外线程的数量,因此如果用户快速连续触发多个工作线程,则很可能会发生这种情况。
有几种方法可以解决这个问题,您可以根据自己的要求选择哪种方法。
如果由于两个线程访问同一内存而发生崩溃,一个简单的解决方案是获取数据的副本。请注意,对于列表、字典等,您需要深度复制数据以确保嵌套值也被复制。对于大数据,这可能会导致一些开销。
您尚未在示例中包含 calc
方法,因此我无法建议如何在您的情况下执行此操作,但一般而言。
from copy import copy
data = 'a simple string'
data_c = copy(data)
或者,深度复制
from copy import deepcopy
data = {'a':'dict', 'of':'items'}
data_c = deepcopy(data)
如果您有一个特定的工作线程,一次只能运行一个,则可以实现原始锁。下面假设您希望最新工作程序始终运行,并在新任务到达时丢弃所有较早的工作程序。
self._worker_lock = False
self._worker_waiting = False
每个工作人员 .finished
信号应连接到执行的方法。
def worker_finised(self):
self._worker_lock = False
if self._worker_waiting:
QThreadPool.globalInstance().start(self._worker_waiting)
self._worker_waiting = False
当前工作线程完成后,这将自动启动下一个工作线程。如果您希望所有发生的工作线程都运行,则可以使用 list
队列。
最后,启动工作线程时。
def plot()
worker = Worker(self.calc)
worker.signals.finished.connect(self.plot_result)
if self._worker_lock:
self._worker_waiting = worker
else:
self._worker_lock
QThreadPool.globalInstance().start(worker)
这是一种愚蠢的方法,它还会阻止您使用线程进行其他计算并使线程池变得无用。
threadpool = QThreadPool()
threadpool. setMaxThreadCount(1)
即使这样,如果绘图和计算方法仍然可以同时执行,这可能还不够,您仍然会崩溃。但如果您的线程仅相互冲突,那就足够了。
关于python - 如何在运行多线程计算然后绘制发出的结果时防止崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54693147/
我有一段代码看起来像这样: void update_clock(uint8_t *time_array) { time_t time = *((time_t *) &time_array[0]
应用程序崩溃了 :( 请帮助我.. 在这方面失败了。我找不到错误?该应用程序可以连接到 iTunesConnect 但它会出错。 谁能根据下面的崩溃报告判断问题出在哪里? share_with_app
小二是新来的实习生,作为技术 leader,我给他安排了一个非常简单的练手任务,把前端 markdown 编辑器里上传的图片保存到服务器端,结果他真的就把图片直接保存到了服务器上,这下可把我气坏了,就
我正在创建一个函数,它将目录路径作为参数传递,或者如果它留空,则提示用户输入。 我已经设置了我的 PATH_MAX=100 和 if 语句来检查 if ((strlen(folder path) +
我已将“arial.ttf”文件(从我的/Windows/Fonts 文件夹中获取)加载到内存中,但是将其传递到 FT_New_Memory_Face 时会崩溃(在 FT_Open_Face 中的某处
我正在尝试在我的计算机上的两个控制台之间进行 rtsp 流。 在控制台 1 上,我有: ffmpeg -rtbufsize 100M -re -f dshow -s 320x240 -i video=
我正在尝试使用 scio_beast在一个项目中。我知道它还没有完成,但这并不重要。我已经设法让它工作得很好。 我现在正在尝试连接到 CloudFlare 后面的服务器,我知道我需要 SNI 才能工作
我有一个带有关联宏的下拉列表,如下所示: Sub Drop() If Range("Hidden1!A1") = "1" Then Sheets("Sheet1").Se
我对 bash 很陌生。我要做的就是运行这个nvvp -vm /usr/lib64/jvm/jre-1.8.0/bin/java无需记住最后的路径。我认为 instafix 就是这样做...... n
我在 Windows 上使用 XAMPP 已经两年左右了,它运行完美,没有崩溃没有问题。 (直到四个月前。) 大约四个月前,我们将服务器/系统升级到了更快的规范。 这是旧规范的内容 - Windows
我面临着一个非常烦人的 android 崩溃,它发生在大约 1% 的 PRODUCTION session 中,应用程序始终在后台运行。 Fatal Exception: android.app.Re
尝试使用下面的函数: public void createObjectType() { try { mCloudDB.createObjectType(ObjectTypeIn
由于我正在进行的一个项目,我在 CF11 管理员中弄乱了类路径,我设法使服务器崩溃,以至于我唯一得到的是一个漂亮的蓝屏和 500 错误.我已经检查了日志,我会把我能做的贴在帖子的底部,但我希望有人会启
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 10 个月前关闭。 Improve
我最近从 xcode 3.x 更新到 4.2,当我在 4.2 中运行应用程序时,我遇到了核心数据问题。我还更新到了 iOS 5,所以问题可能就在那里,我不太确定。 这些应用程序在 3.x 中运行良好,
我是一个相对较新的 iPhone 应用程序开发人员,所以我的知识有点粗略,所以如果这是一个微不足道的问题,请原谅我。 我有一个导航应用程序,它通过在navigationController对象上调用p
if ([MFMailComposeViewController canSendMail]) { MFMailComposeViewController *mailViewController
你能帮我吗? 我正在设置 UILocalNotification,当我尝试设置其 userInfo 字典时,它崩溃了。 fetchedObjects 包含 88 个对象。 这是代码: NSDi
为什么我的代码中突然出现 NSFastEnumeration Mutation Handler 崩溃。我很茫然为什么会突然出现这个崩溃以及如何解决它。 最佳答案 崩溃错误: **** 由于未捕获的异常
当我从表中删除行时,我的应用程序崩溃了。这是我检测到错误和堆栈跟踪的来源。谢谢! //delete row from database - (void)tableView:(UITableView *
我是一名优秀的程序员,十分优秀!