提问人:Mohan S 提问时间:10/20/2023 最后编辑:Mohan S 更新时间:10/27/2023 访问量:139
中继器模型在复制项目时非常慢
Repeater model very slow when copying an item
问:
我们在项目中面临性能问题。我们正在使用Qt/QML和C++后端,我们正在开发网格按钮。如果我们要更改或更新数据模型,则中继器部分需要更多延迟来更新所有按钮,因此 UI 非常慢。根据按钮的数量,延迟会增加,如果更新了 64 个按钮,则意味着加载需要 6 秒。
当我们尝试更新数据或将对象数组复制到 Repeater 的模型容器(数据模型)中时,复制所有项目会消耗更多时间。例如,30 个对象消耗 2 秒。如果对象计数增加,则消耗的时间也会按比例增加。
根据控制台调试打印,执行此行后,执行下一个命令需要 2 秒。console.log("GRID update data model")
如何避免中继器的这种延迟?
- 目标处理器名称:IMX537
- Qt版本:Qt 5.15.2(GCC 9.3.0,64位)
注意:此延迟问题仅发生在目标设备中。在本地编译中没有看到这种延迟。
法典:
function handleModelChanged() {
delegateModel.model = areaViewModel;
const newUiType = areaViewModel.uiType
if (newUiType !== uiType || !modelDataIsEqual(delegateModel, dataModel) ) {
var buttons = []
for (var row = 0; row < delegateModel.model.rowCount(); row++) {
var item = delegateModel.items.get(row).model;
var button = dataModelItemToButton(item);
buttons.push(button);
}
console.log("GRID clear data model")
dataModel = []
console.log("GRID change uiType " + uiType + " -> " + newUiType)
uiType = newUiType
console.log("GRID update data model")
dataModel = buttons;
console.log("GRID buttons changed uiType=" + uiType + " cls=" + areaViewModel.callClass);
}
}
Repeater
{
id: areaRepeater
model: dataModel
delegate: {
gridButton;
}
onItemAdded: {
if (index == areaRepeater.count - 1) {
console.log("GRID repeater added " + areaRepeater.count + " buttons")
updateItems()
}
}
}
}
function modelDataIsEqual(modelData, data) {
if (!modelData || !data || modelData.model.rowCount() !== data.length)
return false;
for (var i = 0; i < modelData.model.rowCount(); ++i) {
const item = modelData.items.get(i).model;
const button = data[i];
if (button.dataAreaShortName !== item.dataAreaShortName ||
button.dataAreaName !== item.dataAreaName ||
button.dataIsExitArea !== item.dataIsExitArea ||
button.dataAreaGridCols !== item.dataAreaGridCols ||
button.dataIsGroupedButton !== item.dataIsGroupedButton ||
button.dataAreaLocked !== item.dataAreaLocked ||
button.dataAreaIcon !== item.dataAreaIcon ||
button.dataIsDopArea !== item.dataIsDopArea ||
button.dataIsSideGroup !== item.dataIsSideGroup ||
dlaButtonStyle !== areaModel.combineBtnStyle ||
oddEvenBtnAppearance !== areaModel.getLockedButtonAppearance() ||
button.dataButtonAppearance !== item.dataButtonAppearance ||
button.dataCrowdedArea !== item.dataCrowdedArea ||
button.dataOverCrowdedArea !== item.dataOverCrowdedArea ||
button.dataPeopleIconArea !== item.dataPeopleIconArea ||
button.dataSideStateIconArea !== item.dataSideStateIconArea)
{
return false;
}
}
return true;
}
function dataModelItemToButton(item) {
if (!item)
return null;
return {
dataAreaShortName: item.dataAreaShortName,
dataAreaName: item.dataAreaName,
dataIsExitArea: item.dataIsExitArea,
dataAreaGridCols: item.dataAreaGridCols,
dataIsGroupedButton: item.dataIsGroupedButton,
dataAreaLocked: item.dataAreaLocked,
dataAreaIcon: item.dataAreaIcon,
dataIsDopArea: item.dataIsDopArea,
dataIsSideGroup: item.dataIsSideGroup,
dataButtonAppearance : item.dataButtonAppearance,
dataCrowdedArea: item.dataCrowdedArea,
dataOverCrowdedArea: item.dataOverCrowdedArea,
dataPeopleIconArea : item.dataPeopleIconArea,
dataSideStateIconArea : item.dataSideStateIconArea
}
}
正如我上面提到的,更多的按钮意味着延迟也会增加。就像 100 毫秒将一个按钮输入模型一样。在某处,提到在 Repeater 中使用 ListModel 来加载数据项。但我也试过了那个,似乎发生了同样的延迟。 我已经检查了我的目标设备的大部分延迟,导致仅执行此行 dataModel = button;我不能忽略这一行,因为,一旦复制到数据模型中,就只能看到所有按钮。还有其他方法可以减少这种延迟吗?
答:
您似乎正在使用 Javascript 数组作为模型。
delegateModel.model = areaViewModel;
这意味着每次进行更改时,都必须将模型替换为包含更改的新 Javascript 数组。但是,必须重新绘制所有记录,即使是以前见过的记录。这种模式的复杂度是 O(N(N+1)/2) 或大致为 O(N^2)。从下表可以看出性能:Repeater
大小 | 总绘制时间 |
---|---|
1 | 1 |
2 | 1 + 2 |
3 | 1 + 2 + 3 |
N | N ( N + 1 ) / 2 |
这很糟糕,因为它是指数级延迟。
在某些平台上,您可能没有注意到这一点,因为 N 很低,或者您的处理器速度足够快。因此,你要做的是将其部署为该平台可接受的解决方案。但是,一段时间后,当该代码成为生产代码时,您的用户将增加 N 超出您的测试限制,并且您的用户会将其作为您需要解决的问题提出。
首选的方法是重构并用 (1) , (2) 或 (3) 新 Qt6.4+ 语法替换。这些模型运行良好,因为它们实现了更改检测,因此只需刷新较新的记录,而不必刷新所有记录。ListModel
QAbstractListModel
list
Repeater
// e.g.
Repeater {
model: ListModel {
id: areaViewModel
}
}
简而言之,不要使用 Javascript 数组作为 .Repeater
评论
上一个:在未连接的表之间创建关系
下一个:筛选 Power BI 中的数据
评论
HashTable