Hi, Sorry for the kinda late response, but you probably would also like to check https://github.com/dkormalev/asynqro <https://github.com/dkormalev/asynqro> for ideas about API improvements.
-- Regards, Denis Kormalev > On Feb 12, 2019, at 1:38 AM, Juan Gonzalez Burgos <juangbur...@gmail.com> > wrote: > > Hi, > > Looking at it with the “Qt Creator” hat on, i.e. with the mindset of “could > we replace what we do in Qt Creator with our extension of QtConcurrent". > (http://code.qt.io/cgit/qt-creator/qt-creator.git/tree/src/libs/utils/runextensions.h > > <http://code.qt.io/cgit/qt-creator/qt-creator.git/tree/src/libs/utils/runextensions.h> > adds the convenience and actual runnable based around QFuture and > QFutureInterface.) > I suppose this is a very UI-interaction focused, and high-level view on > things ;) but it is something that the > QFuture/QFutureInterface/QFutureWatcher API supports. > > Wow, first of all thanks for taking the time for this awesome feedback. > I guess the QFuture/QFutureWatcher design was driven by Qt's needs as I > developed QDeferred for my very own needs. I suppose one just have to use the > tool that best fits the problem. > > 1) I think the chaining/promises style is an improvement to the need to > always use QFutureWatcher. We more often need to carry a QFutureWatcher > member around than I like (even with a helper function Utils::onResultReady, > the moment you need to handle various signals you’ll want to stick to a > single QFutureWatcher) > > Agree. There are use cases where QFutureWatcher is better. > > 2) We use QFuture/QFutureInterface for a generic progress UI. Basically you > tell a central progress UI manager about your QFuture, and that shows a > progress bar for it, including a cancel button. > > What about multiple “subscribers” to a task? The progress UI needs to act on > progress info, and finished / success status changes. On a glance I didn’t > see if that is possible with your API. > > Yes is possible to have multiple subscribers, thank you for pointing at it, I > forgot to mention it explicitly in the readme. It is done as follows: > > QDeferred<int> defer = myMethod() > .done([](int val) { > > }) > .fail([](int val) { > > }); > > // we can pass "defer" around since is a explicitly shared object > // ... > > // subscribe elsewhere > defer > .done([](int val) { > > }) > .fail([](int val) { > > }); > > And if the QDeferred was already resolved/rejected when a new subscription is > done, then the callback is called inmediatly (depending on the > connection-type, more on this later). I will add this to the document. > > I didn’t see cancel functionality in your work, do you have thoughts on this? > > I didn't think of this, haven't had the need but it is a great idea! I think > it should not be too hard to implement. Maybe an API method called "cancel" > and a callback called "cancelled" so we know when the process has actually > been cancelled, > > The implementation for progress seems to be a bit awkward in comparison to > QFutureInterface, and doesn’t seem to be separate from the result type? > Progress can be pretty separate from actual result producing, i.e. a file > system search will be able to provide very fine grained progress information, > but might only report a handful of results. > > Yes and no, actually this was a hard decision for me. One main differentator > with QDeferred is that there are N result types, so we could get around the > issue as follows: > > QDeferred<QByteArray, int, QString> defer = myMethod() > .progress([](QByteArray result, int progress, QString message) { > Q_UNUSED(result); > qDebug() << "Progress" << progress << "% , details :" << > message; > }) > .done([](QByteArray result, int progress, QString message) { > Q_UNUSED(progress, message); > // do something with the QByteArray results > }); > > The fact that you have N result types does not mean you have to use all of > them in every callback. You could use some of them for progress info and some > others for results. I know this might come as "akward", but what actually > constitute a "progress"? At some point I though of adding a specialized <int> > or <QString> API for the progress but decided not to because it would be > limiting. E.g. one of my use cases was to bring large chunks of historic data > from a server, and the "progress" for that use case was partial data blocks > which I could inmediatly display in a chart as they arrived, so one of my > return types was a reference to that partial data block which I only used in > the progress callback. Maybe there is a better way to achieve this, but I > couldn't find one that met all my needs. > > Another thing that QtConcurrent handles for us, it to guard against “too much > progress reporting”. I.e. if a loop from 1 to 1000000 reports every single > step as progress, this would block the UI/main thread with progress updating. > QtConcurrent makes sure that actual progress reporting to the receiving > thread only happens in “sensible” intervals. > > This sounds like a good idea, but makes me wonder; isn't it the reponsibility > of the user to create sensible reporting? I mean, I could drown my CPU with a > for-loop, is it the fault of the for-loop or my fault for using it > incorrectly? Nevertheless it is indeed always a good idea to program in a > defensive way. Can I ask how does Qtconcurrent implements this protection? > > One nice thing about QFuture/QFutureInterface is that one doesn’t actually > need to create an _actual_ async task to use the same functionality. We use > that at a few places for showing progress for things that are not actually > running in a thread, but wait for other asynchronous tasks to finish (e.g. > QProcess). But that’s just a convenience that avoids having a separate API > for it. > > Ah, something else I didn't document, I am sorry. QDeferred works similar to > Qt signals and slots in the sense that it has a "Qt::ConnectionType" as an > argument when defining each callback. So QDeferred also works within the same > thread: > > defer.progress([](int val) { > qDebug() << "Counting in the same thread :" << val; > }, Qt::DirectConnection); > > for (int i = 0; i < 100; i++) > { > defer.notify(i + 1); > } > > The progress callback will be called, eventhough the notify is done in the > same thread. > > 3) Reporting intermediate results is something that we heavily use for things > like e.g. the search functionality. While the search is running, you want the > UI to already present what was found so far. > > That is what I tried to achieve with the progress callback as it is, but I > understand there is still room for improvement in the API. I will give it > more thought. > > Thanks again for the feedback. > > On Tue, Feb 12, 2019 at 8:02 AM Eike Ziller <eike.zil...@qt.io > <mailto:eike.zil...@qt.io>> wrote: > Hi, > > Looking at it with the “Qt Creator” hat on, i.e. with the mindset of “could > we replace what we do in Qt Creator with our extension of QtConcurrent". > (http://code.qt.io/cgit/qt-creator/qt-creator.git/tree/src/libs/utils/runextensions.h > > <http://code.qt.io/cgit/qt-creator/qt-creator.git/tree/src/libs/utils/runextensions.h> > adds the convenience and actual runnable based around QFuture and > QFutureInterface.) > I suppose this is a very UI-interaction focused, and high-level view on > things ;) but it is something that the > QFuture/QFutureInterface/QFutureWatcher API supports. > > 1) I think the chaining/promises style is an improvement to the need to > always use QFutureWatcher. We more often need to carry a QFutureWatcher > member around than I like (even with a helper function Utils::onResultReady, > the moment you need to handle various signals you’ll want to stick to a > single QFutureWatcher) > > 2) We use QFuture/QFutureInterface for a generic progress UI. Basically you > tell a central progress UI manager about your QFuture, and that shows a > progress bar for it, including a cancel button. > > What about multiple “subscribers” to a task? The progress UI needs to act on > progress info, and finished / success status changes. On a glance I didn’t > see if that is possible with your API. > > I didn’t see cancel functionality in your work, do you have thoughts on this? > > The implementation for progress seems to be a bit awkward in comparison to > QFutureInterface, and doesn’t seem to be separate from the result type? > Progress can be pretty separate from actual result producing, i.e. a file > system search will be able to provide very fine grained progress information, > but might only report a handful of results. > Another thing that QtConcurrent handles for us, it to guard against “too much > progress reporting”. I.e. if a loop from 1 to 1000000 reports every single > step as progress, this would block the UI/main thread with progress updating. > QtConcurrent makes sure that actual progress reporting to the receiving > thread only happens in “sensible” intervals. > > One nice thing about QFuture/QFutureInterface is that one doesn’t actually > need to create an _actual_ async task to use the same functionality. We use > that at a few places for showing progress for things that are not actually > running in a thread, but wait for other asynchronous tasks to finish (e.g. > QProcess). But that’s just a convenience that avoids having a separate API > for it. > > 3) Reporting intermediate results is something that we heavily use for things > like e.g. the search functionality. While the search is running, you want the > UI to already present what was found so far. > > > Br, Eike > > > On 11. Feb 2019, at 12:49, Juan Gonzalez Burgos <juangbur...@gmail.com > > <mailto:juangbur...@gmail.com>> wrote: > > > > Hi guys, > > > > Sorry to bother you with yet another promise/deferred library for Qt. I am > > looking for feedback. > > > > https://github.com/juangburgos/QDeferred > > <https://github.com/juangburgos/QDeferred> > > > > Thanks. > > _______________________________________________ > > Development mailing list > > Development@qt-project.org <mailto:Development@qt-project.org> > > https://lists.qt-project.org/listinfo/development > > <https://lists.qt-project.org/listinfo/development> > > -- > Eike Ziller > Principal Software Engineer > > The Qt Company GmbH > Rudower Chaussee 13 > D-12489 Berlin > eike.zil...@qt.io <mailto:eike.zil...@qt.io> > http://qt.io <http://qt.io/> > Geschäftsführer: Mika Pälsi, > Juha Varelius, Mika Harjuaho > Sitz der Gesellschaft: Berlin, Registergericht: Amtsgericht Charlottenburg, > HRB 144331 B > > _______________________________________________ > Development mailing list > Development@qt-project.org > https://lists.qt-project.org/listinfo/development
_______________________________________________ Development mailing list Development@qt-project.org https://lists.qt-project.org/listinfo/development