Solved Combine QtConcurrent call
-
I have three methods and all of them returns a string, I want to run all of them using
QtConcurrent
and get their return into a single list or something like that.QtConcurrent::mapped
is ideal as it returns an iterator but I can only run one method at time.
in JavaScript there'spromise.all([method_a, method_b, method_c])
it will automatically merge their return into a single result (iterator).
How to do that in Qt? -
Do you have something like this?
/*static*/ QString MyClass::methodA(const QString & val){/*do something*/ } /*static*/ QString MyClass::methodB(const QString & val){/*do something*/ } /*static*/ QString MyClass::methodC(const QString & val){/*do something*/ } void MyClass::runCalculation(){ QStringList myList; // fill the list QFuture<QString> futRes = QtConcurrent::mappedReduced( myList.cbegin(),myList.cend(), [](const QString & val)->std::tuple<QString,QString,QString>{return std::make_tuple(MyClass::methodA(val),MyClass::methodB(val),MyClass::methodC(val));} , [](QString& base,const QString & result){base+=result;} );
-
[](const QString & val)->std::tuple<QString,QString,QString>{return std::make_tuple(MyClass::methodA(val),MyClass::methodB(val),MyClass::methodC(val));} , [](QString& base,const QString & result){base+=result;}
Blimey! :-;
-
@VRonin I forgot to mention two things:
1 - The methods are in different classes.
2 - It may exist one or more than one methods, maybe even ten, the thing is that I have a collection of objects and all of them implement the same method calledsearch
, I want to call thesearch
method from all the objects concurrently and get their results in a single list. -
@Mr-Gisa said in Combine QtConcurrent call:
objects and all of them implement the same method called search
Looks like you are describing a problem C++ was born to solve: polymorphism
- Are they
QObject
s (or, at leastQ_GADGET
s)? - Do they all inherit from the same base class that implements a virtual method called
search
?
If both answers are no then I'm afraid you are out of luck
- Are they
-
How about this:
- Create a wrapper class that takes a std::function as a parameter
- Offer a public method on that class that will run whatever std::function is set, and store the resulting string in a member variable
- Create a list of those wrapper classes and set the correct functions on each
- Use the list in QtConcurrent::map or similar
- Read the string results from the members of the wrapper classes
-
Good idea but it think it can't be compiled (I did not test).
std::function
is a template and needs to be fully qualified. So you either:- specify the template parameters of the wrapper member fixing what function
search
must be - make the wrapper a template but then you can't store different specialisations of the same template in the same container
I still think polymorphism is not just the right answer here but the only acceptable one
@Mr-Gisa
can you give us a rough example of what "collection" and "objects" means in your case? - specify the template parameters of the wrapper member fixing what function
-
@VRonin said in Combine QtConcurrent call:
Good idea but it think it can't be compiled (I did not test).
std::function
is a template and needs to be fully qualified. So you either:- specify the template parameters of the wrapper member fixing what function
search
must be - make the wrapper a template but then you can't store different specialisations of the same template in the same container
I still think polymorphism is not just the right answer here but the only acceptable one
@Mr-Gisa
can you give us a rough example of what "collection" and "objects" means in your case?Well, OP didn't specify whether the methods have different signatures. But even if they have, you may be able to use
std::function<QString()>
and provide the needed parameter in the bind call, like so:
auto myFunction = std::bind(&MyClass::MyMethod1,this,parameter1,parameter2,parameter3);
Assuming MyMethod returns a string, that should work.
- specify the template parameters of the wrapper member fixing what function
-
@Asperamanca said in Combine QtConcurrent call:
you may be able to use
std::function<QString()>
Variadic template specialisation is just too much for my little brain to process. I'm still not convinced but certainly not smart enough to say it's defenetly not going to work
-
@VRonin
I think both approaches would work in this case. If OP says he has different classes, but each has a "Search" method, creating a "Searchable" interface and making the Search method virtual sounds like a good approach. -
@Asperamanca @VRonin I think that the best way for me to explain in showing some code. This is an example of what I'm planning to do.
And beforehand: I put the classes instances in a container cause each one of those classes will be a plugin and will be loaded using
QPluginLoader
later on, so in order to minimize the problem I just put it in a kind of container.Here you can see the example code: https://pastebin.com/raw/7BwgppwQ
As I will be processing heavy operations (like http requests, parsing, etc) in each
search
method I wanted to call it asynchronously and so I though thatQt Concurrent
would help me with that.
And another thing: as I want the result of all the classes into a singleQList
I put aQString
inside theResult
struct to identify the site that it has been found (maybe I could use the pointer likeQModelIndex
does?).So yeah, that is what I want to do.
-
One thing is missing before we can write the solution: what should be passed as argument to
search()
?Also keep in mind that accessing the values in the container before the end of the concurrent process is a race condition
-
The argument is just a string that will be used as query, this is just a prototype. But it's just a string.
Also keep in mind that accessing the values in the container before the end of the concurrent process is a race condition.
I want to create a kind of real time searcher, like when the user type a query it will async call all the search method from all the websites and in real time while it's finding the results I want to put all the results in a list view.
-
-
@VRonin Is it too early to say that I'm falling in love with you even without calling you out for dinner? haha, just kidding, you rock!!!
Thank you very much.
Just one last question:
Probably I will create a custom model and delegate to display the items so I was wondering, if I want to create a kind of status for eachResult
and update them in real time on the view I have to use a kind of struct inside theResult
with the status types and use signals and slots to update that right? -
@Mr-Gisa said in Combine QtConcurrent call:
update them in real time on the view
You'd have to store the result inside the
ISearchable
class and then useQFutureWatcher::resultAt
, it's a bit more involved@Mr-Gisa said in Combine QtConcurrent call:
Is it too early to say that I'm falling in love with you even without calling you out for dinner?
Qt Forum is the new Tinder
-
You'd have to store the result inside the ISearchable class and then use QFutureWatcher::resultAt, it's a bit more involved.
I would love some help with that, for real.
I was reading the docs and I saw that Qt has
QFutureSynchronizer
that syncs multipleQFuture
, what is the difference between what we are doing here andQFutureSynchronizer
?I changed the sleep time of
SiteA
in order to check what happens and it freezes even ifSiteB
finished already its results. I really wanted that to display to the list view right when the results are ready.