Details
-
Bug
-
Resolution: Done
-
P1: Critical
-
5.11.1
-
None
-
1) Qt 5.11.1 (x86_64-little_endian-lp64 shared (dynamic) release build; by Clang 8.1.0 (clang-802.0.42) (Apple))
2) Qt 5.11.1 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 8.1.1 20180531) Linux yoga 4.17.2-1-ARCH
3) Qt 5.11.1 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2017)
1) Qt 5.11.1 (x86_64-little_endian-lp64 shared (dynamic) release build; by Clang 8.1.0 (clang-802.0.42) (Apple)) 2) Qt 5.11.1 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 8.1.1 20180531) Linux yoga 4.17.2-1-ARCH 3) Qt 5.11.1 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2017)
Description
Consider these two code snippets:
for (var i = 0; i < n; i++) { var message = getMessage(i); if (!known[message.id]) known[message.id] = true }
var messages = []; for (var i = 0; i < n; i++) { messages.push(getMessage(i)); } for (i = 0; i < messages.length; i++) { var message = messages[i]; if (!known[message.id]) known[message.id] = true; }
I would expect the first to be faster.
In fact, the first snippet is more than ten times slower than the second one for some reason.
—
See the example below:
import QtQuick 2.11 Item { Component.onCompleted: { for (var i = 0; i < 4; i++) { process(true) process(false) } } function process(fast) { var message, i; var start = Date.now() var known = {}; var messages = []; for (i = 0; i < 10000; i++) { message = Math.random().toString(); messages.push(message); if (!fast && !known[message]) known[message] = true; } for (i = 0; i < messages.length; i++) { message = messages[i]; if (fast && !known[message]) known[message] = true; } console.log(fast ? 'fast' : 'slow', (Date.now() - start) / 1000) } }
For the testcase, messages are just random strings. In the original code, those were unique id strings from the database (also messages were objects, and `known` stored their `.id`s).
Output on my setup on Qt 5.11.1:
qml: fast 0.087 qml: slow 1.178 qml: fast 0.097 qml: slow 1.532 qml: fast 0.117 qml: slow 2.376 qml: fast 0.157 qml: slow 3.7
—
The following testcase shows that the slowdown grows on subsequent calls (despite all variables being local):
import QtQuick 2.11 Item { Timer { id: timer interval: 100 running: true onTriggered: process() } function process() { var fast = false //true var message, i; var start = Date.now() var known = {}; var messages = []; for (i = 0; i < 10000; i++) { message = Math.random().toString().split().join(); messages.push(message); if (!fast && !known[message]) known[message] = true; } for (i = 0; i < messages.length; i++) { message = messages[i]; if (fast && !known[message]) known[message] = true; } console.log(fast ? 'fast' : 'slow', (Date.now() - start) / 1000) timer.restart() } }
Result:
qml: slow 0.638 qml: slow 1.29 qml: slow 2.05 qml: slow 3.034 qml: slow 4.246 qml: slow 5.422 qml: slow 7.219 qml: slow 9.395 qml: slow 11.192 qml: slow 12.359 qml: slow 12.329 qml: slow 13.73 qml: slow 14.954
Even if you change the number of loop iterations (aka the object size) in the testcase from 10000 to 100, it eventually starts to take seconds to do anything.