[Interest] [External]Re: How to get QtConcurrent to do what I want?

Scott Bloom scott at towel42.com
Tue Feb 1 18:48:02 CET 2022

Depending on your QFuture setup, you could monitor each tile, and when it completes, update the min max...

Passing the manager to each tile, and when the tile is finished update the manager with the tiles value.  Then a simple mutex should allow you to not collide.  No signals, just a simple function call.

When the future watcher says all tiles are done, you will also have the min/max computed at that point, so you can kick off phase 2.

While I love the signal slot for "generic, I don’t know who needs this information" type design. Sometimes the cost/overhead of being a qobject and sending the signal, especially when it’s a very discrete "signal" and not generic in any means, it can be overkill.

To me, the manager you have doesn’t need to know "is a tile finished", ie a generic signal.  But rather what Is the min max of the tile when finished a specific signal.  For that level, a simple function works.


-----Original Message-----
From: Interest <interest-bounces at qt-project.org> On Behalf Of Murphy, Sean
Sent: Tuesday, February 1, 2022 9:32 AM
To: interest at qt-project.org
Subject: Re: [Interest] [External]Re: How to get QtConcurrent to do what I want?

> 😊  that definitely does.
> Of course.... I wonder if you had removed that, but left in the 
> QObject etc etc, what would it have been.  Likely, not much worse than 15ms.

Yep, once I removed the random generator object, I had the same thought: 
"could I go back to QObject?!?!", but as you mention, I don't think there's any reason for me to do that, unless I can think of a reason that I need to provide some sort of signal down at a tile level beyond just completion progress (since QFutureWatcher can handle the progress part). 

The only potential signal that comes to mind is between the tile::load() and tile::remap() steps I do need to know the min/max raw data values to compute what the remap parameters are. Currently I have to wait for the loadFutureWatcher to report it is finished, then I take a pass through every tile to calculate the global min/max values, then I can kick off the remap process with those parameters in hand. If the tile was an QObject and it emitted a signal to relay that information back then the global min/max is getting updated as each tile completes its first step, which means as soon as the last tile finishes, I'm good to go with the remap step instead of taking that pass through all the tiles to determine the global min/max.

But I could also accomplish the same thing by modifying the loadTIle function that is passed to QtConcurrent to return a QPair<double, double> instead of returning void like it currently is Does. Then I would connect the future watcher's resultReadyAt(int index) signal to a slot in my tile manager that accomplishes the same thing, without making my tile class inherit from QObject.

> Why? IMO, Qt wouldn’t be what it is today, if simply allocating 60k 
> QObjects and connecting a signal to them too that long.
> But I think the overall architecture of what you have now, is MUCH 
> better and will scale to a more complex "actually do the work" system 
> much better than the other.

I think I'm happy with it as a proof-of-concept design as I have it now - or at least once I replace the placeholder delays with the code that actually works on the data file. After that, I want to also implement the idea Konstantin suggested of just dividing the original image up into
QThread::idealThreadCount() blocks and then compare the results on actual data and see which performs better. I'm guessing it'll be the latter since on my idealThreadCount() == 8 system, there's probably way less overhead in creating 8 things that do the work than 60,000+. 
Especially since the 60,000 items are still going to be funneled through 8 threads anyways.

Interest mailing list
Interest at qt-project.org

More information about the Interest mailing list