Hello,
on n'a pas mal argumenté le pour et contre le COW dans Qt,
http://blogs.qtdeveloper.net/archive...it-2/#more-158
Qu'en pensez-vous ?
Hello,
on n'a pas mal argumenté le pour et contre le COW dans Qt,
http://blogs.qtdeveloper.net/archive...it-2/#more-158
Qu'en pensez-vous ?
http://blog.developpez.com/index.php...&c=1&tb=1&pb=1
Je suis content qu'il ait démontré que la méthode de Trolltech soit plus rapide. Après les tests de Sutter, j'avais un doute, mais les optimisations de Qt ont fait le travail + les QString ne sont pas les plus critiques pour ce genre de choses - imaginez les benchmarks sur des QList ! -
Je me pose la question d'inclure un pointeur Qt plutôt qu'un pointeur Boost dans ma bibliothèque matricielle...
tu revises donc ta position ?
qu'entends-tu par les benchmarks sur les lists ?
Les QList sont aussi partagées implicitement.
En fait, je n'avais jamais eu de position fixe![]()
oui c'est clair, les Qlist ca evite beaucoup de recopie et permet un design plus propre en retournant la liste.
mais tu n'etais pas pour la stl a tout pris ?![]()
enfin tout le monde peut changer d'avis hein ?![]()
Comme l'a dit je ne sais plus qui : Il ne faut jamais croire un benchmark que l'on n'a pas truqué soit-même
En l'occurence, je n'ai pas eu l'occasion de le tester sur ma machine, de jouer avec... Je ne dis pas que je j'y crois, ni que je n'y crois pas.
Par contre, en jettant un oeil rapide sur le code, je ne vois pas en quoi les chaînes sont partagées entre les différent thread ?
Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.
Le comportement de std::string dépend de l'implémentation, cellede libstdc++ utilise déjà du copy-on-write et pas vraiment de manière optimisée pour le multithreadé d'après ce que je sais.
Et en regardant les résultats des benchmarks je ne vois rien qui explicite que les solutions de Qt sont mieux.
J'ai survolé les benchs.
Comme je disais par mail à Aurélien. La pertinence du COW m'échappe toujours.
Je veux bien volontier admettre un intérêt à des chaînes non mutables partagées. Mais pas à des COW partagées dans divers threads.
Mes scénarios de manipulation de chaines consistent généralement à construire ces chaines et à ensuite les figer. Après éventuellement elles sont dans des tâches (ace) partagées entre plusieurs threads, ou expédiées d'une tâche à l'autre. Et si j'avais des modifs à faire, cela correspondrait à des reset, mais pas à des utilisations de [] ou de quoique ce soit qui active une copie sur écriture.
Du coup les benchs qui me semblent les plus pertinents (je ne les ai plus en tête) sont ceux:
- de construction (et encore)
- ceux d'accès "globaux" pour quand on veut sérialiser vers une autre structure ; on utilise alors directement le pointeur sous-jascent ; ne devrait pas couter grand chose, même avec du COW
- ceux d'accès "atomique" pour ceux qui ecrivent des boucles avec [] sur tous les éléments des chaines ; là le COW ne devrait pas être si bon je pense.
Le coût de la copie de type chaine à type chaîne ? Est-ce si pertinent ?
Mes paramètres sont pris par référence constante (ce qui n'est pas le cas d'un de leurs benchs). Je ne fais pas de copies pour le plaisir de faire des copies -- à la limite pour un nouvel object qui recopie la chaine reçue lors de sa construction, ici OK pour des non-mutables partagées et réinitialisables.
Mes retours vont utiliser RVO et RNVO (quand possible), un jour les lvalue reference (je l'espère). Là effectivement, on n'a pas de sémantique de déplacement native... OK pour cet avantage là. Bien que la non-mutable partagée est très bien aussi, voire carrément que le comptage non protégé contre le multithread. (*)
(*) Dans le genre il aurait fallu un constructeur à std::list qui prenne un std::auto_ptr<std::list> et qu'il s'implémente par un swap. Bon, c'est sale et cela fait plus de types, et cela empêche les R*VO, c'est vrai.
Pour les concaténations, il existent d'autres techniques qui torchent (cf les concatenators présentés par Matthew Wilson dans Imperfect C++ et donc présents dans stl_soft -- bien que je serais plus parti sur une approche de meta-prog plutôt que l'approche dynamique qu'il a choisie)
Pour revenir à QT, vu qu'ils utilisent un proxy, cela mérite de ressortir le MEC++ pour voir si il n'y aurait pas des effets de bord bizarres.
Je suis aussi très surpris des résultats de GCC. Je savais pour le COW, mais je vois rien qui justifie les écarts. A part une très mauvaise implémentation du comptage atomique, ou d'autre chose.
A propos de RVO/RNVO je me demande qu'elle sont les options de compils retenues dans les bench vu les coûts de certains appels. Bref, il faudra que je remesure tout cela chez moi.
Je ne vois pas pourquoi les pointeurs intelligents de QT seraient plus efficaces que ceux de boost qui reposent aussi sur des compteurs atomiques (ou non dans le cas de boost compilé en mono-thread). Sans parler de la richesse de l'interface qui fait que les boost::shared_ptr sont en fait des shared_ressource.
PS: dès que j'ai un moment je m'occupe sérieusement de ces transcripts :-(
Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...
Pou Qt, il faut aussi voir ça de manière plus générale que juste pour les string. Ils partagent ainsi les données de toutes leurs classes qui ont un minimum de données - P_IMPL idiome pour assurer une compatibilité binaire entre les versions de Qt -.
Pour des caînes partagées entre les threads, dans Qt3, ce n'était pas le cas, et apparemment ils ont eu un retour négatif sur ce problème car on devait forcer la copie complète. Maintenant, on peut s'en passer, c'est plus transparent. De plus, leur comptage atomique est efficace, du moins plus efficace qu'une recopie, et leurs mutex qui utilisent aussi leur classe atomique est plus rapide qu'un mutex traditionnel.
Voir aussi:
http://blogs.qtdeveloper.net/archive...the-benchmark/
Pour info, l'auteur de ce benchmark a été interviewé par developpez.com quelques jours avant de publier ses résultats. On va bientôt publier tout ça... (ben oui je fais du teasing)
rvalue references plutôt non ?un jour les lvalue reference (je l'espère)
De manière dynamique, une structure comme sgi rope devrait aussi fournir de bons résultats pour la concaténation.Pour les concaténations, il existent d'autres techniques qui torchent
Il y a un truc que je trouve louche là.Envoyé par Miles
Si on pouvait implémenter des mutex avec des compteurs atomiques, pourquoi est-ce que les autres implémentations de mutex ne procèderaient pas aussi de la sorte pour avoir un truc plus efficace ?
(ceci n'est pas une question comme dans "je connais la réponse, mais pose toi aussi la question". Mais comme dans "je n'en sais strictement rien". Je ne me suis jamais posée cette question)
arf. Oui au temps pour moi. Je me plante toujours.Envoyé par loufoque
Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...
Note: je suis quelqu'un de très atypique en ce qui concerne la programmation multithread. Je joue encore avec, mais mon expérience est essentiellement dans le cadre de programmation en Ada, il y a une dizaine d'année. Je peux être complètement à côté de la plaque.Envoyé par Luc Hermitte
Un mutex doit nécessairement recourir à l'OS s'il ne peut pas se contenter d'être du polling sur une variable, consommant du CPU pour rien. Une possibilité est que les mutex de QT fasse un peu de polling avec des algo lock-free (éventuellement un seul passage peut être un gain) puis prennent un lock via l'OS. On a un gain si la lib n'utilise pas déjà ce truc (ce qui m'étonnerait un peu, je le connais et je suis plutôt rouillé en la matière) et que le lock est généralement soit libre soit pris par un process tournant sur un autre processeur qui le libère rapidement.
vous etes vraiment sure que les mutexes dans Qt sont implementés avec des compteurs atomiques ?
moi je ne pense pas du tout.
C'est ça, je crois. En tout cas, s'ils l'utilisent, c'est après avoir vérifié dans la doc et dans les benchs qu'un mutex traditionnel comporte beaucoup d'aller-et-venues, et avoir une opération atomique pour tenter d'avoir un lock est plus rapide tout de même.Envoyé par Jean-Marc.Bourguet
Je pense serieusement que les compteurs atomiques sont seulement utilisés pour le implicit sharing.
... atomic counting n'est pas de la mise en attente du thread sur une resource protégé
Dans les opérateurs atomiques, il n'y a pas que l'incrémentation, il y a aussi le set and test, et ça, ça sert pour les mutex. Et c'est certain qu'ils s'en servent cf un article dans qqs jours sur "Qt in depth".
Parce qu'on veut dans certains cas en avoir plus ? Par exemple, sous windows, un mutex est partageable entre processus. Il y existe aussi un objet (mal) nommé CriticalSection, qui est en fait un mutex non partageable entre processus, et qui a de bien meilleures perfs.Envoyé par Luc Hermitte
Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.
a priori qt se sert du comptage atomique pour faire des mutexes recursifs.
mais le wait et le wakeup utilise bien un mutex pthread (sous macos)
a+
Oui, il utilise un mutex standard après. Mais au départ, pour accélerer, il utilise un test and set atomique - j'ai l'info directement du concepteur du système... -
Partager