Наконец то я понял о какой производительности идет речь. А теперь из той же документации:
In summary, QVarLengthArray is a low-level optimization class that only makes sense in very specific cases. It is used a few places inside Qt and was added to Qt's public API for the convenience of advanced users.
Во первых, необходимость в этом классе редка и связана она с накладными расходами на выделение динамической памяти, что естественно больше. Я знаю только два случая, когда это становится ощутимой проблемой — в embedded разработке и высоконагруженных приложениях. В первом случае стараются выделить в куче (или в стеке если размер позволяет) память заранее и затем её распределять, например через placement new или просто вручную. Во втором переопределяют операторы new и delete глобально и оптимизируют выделение памяти. Оба этих варианта решают проблему глобально, без допольнительных специальных классов типа std::array или QVarLengthArray. А вот использование стековой памяти неявно где это только возможно чревато проблемами в той же embedded разработке, я полагаю.
Во вторых, исходя из той же документации, это был внутренний класс Qt который они использовали, а значит вполне возможно используется и в контейнерах, и вытащили его на тот случай, если он пригодиться. Мне вот не пригодился ни разу.
std_vector[0] превращается компилятором в *(std_vector.data_pointer), то строка вида qvector[0] будет превращаться в *(qvector.shared_pointer->data_pointer), что уже плохо для процессора.
Нет, у QVector вместо оператора [], нужно вызывать метод at для извлечения элементов, он напрямую обращается к памяти по указателю. Можете посмотреть исходники QVector и проверить. Это идет в разрез с устоявшемся в stl operator [] и методом at, где смысл примерно наоборот этих методов, но контейнеры qt были когда stl еще не был стандартом.
Так я и написал, что подобная оптимизация встречается только у std::string и только для коротких строк. Но в любом случае и std::vector и std::string с длинными строками всё равно намного эффективнее реализаций из Qt, в которых получается двойная косвенность.
Эффективнее тем, что память выделяется в стеке, а не в куче? А есть какие нибудь статьи которые сравнивают производительность хранения в этих областях памяти? И вообще, это так принципиально хранить строки крайне производительно?
Вот как раз повсеместное использование ссылочных типов — это и есть несоответствие стилю современного C++, которые ориентирован скорее на типы-значения.
Просто забудьте как устроен implicit sharing и думайте что в qt move семантика повсеместна. Потому что это практически одно и тоже по производитльности (дайте мне бенчмарки где это опровергается). Я вообще считаю, что move семантика еще один способ выстрелить себе в ногу:
Если говорить, об изменениях, которые имели негативный эффект, то совершенно точно это rvalue ссылки. Они очень мощные, но их очень сложно использовать правильно и слишком легко — неправильно. Я сам научился использовать их строго только в тех случаях, в которых я абсолютно уверен.
— цитата от сюда. Сами создатели стандарта это утверждают.
Так там же как раз есть всё, кроме GUI библиотеки. )))
Есть, свои контролы которые отрисовываются в opengl.
Если мы пишем где-то vector x; (или любой другой контейнер из стандартной библиотеки C++), то это означает, что в стеке располагается несколько int'ов + указатель на реальные данные в динамической памяти. Это конечно тоже не идеал (идеал — это если бы данные прямо в стеке были, кстати, большинство реализаций std::string имеют оптимизацию, которая для малых строк размещает их прямо внутри объекта, на стеке), но работает не плохо, т.к. современные процессоры уже научились оптимизировать подобный код.
Для строк это еще более менее применимо. Но хранить вектор в стеке — это как вообще? Как это будет вообще работать в embedded, где размер стека часто бывает сильно ограничен?
Так я про это и говорил, что я этого не знаю (как и вы оказывается), потому что использую другие механизмы для многопоточности и соответственно не проверял сам руками. Но если они это не поправили, то это может оказаться весьма неприятным сюрпризом для многих программистов, уже привыкающих к современному стандарту.
Я подозреваю, если передаются implicit sharing, то разницы вообще не заметят эти самые программисты. Зато дополнительные трахи с rvalue семантикой очень можно приобрести. Меня поэтому это вообще не заботит, я кстати тоже программист С++, который не брезгует новым стандартом.
В Qt кривая архитектура по многим пунктам (и ненужный препроцессор и несоответствие современному C++ стилю и ещё много чего) и вот это несколько мешает, хотя не критично (да и всё равно конкурентов нет).
Я не вижу где она кривая в упор. Зато неоднократно видел кривость решений где "Qt только для интерфейсов".
Соответственно лично я хотел бы в идеале иметь чисто GUI библиотеку (а не «фреймворк всего») с возможностями уровня Qt и таким же набором поддерживаемых платформ. При этом написанную в стиле современного C++. Это был бы идеал. Но такого к сожалению не существует, поэтому живём с чем есть — с Qt. )))
В каком-то смысле да. Но только весьма неудобная, т.к. ограничивает взаимодействие рамками прописанных сигналов/слотов.
Любая технология ограничена какими то рамками. И Qt не исключение.
Вот как раз такие схемы и являются очень нехорошими с точки зрения производительности. Потому что добавляют лишний уровень косвенности и соответственно в таком случае кэш процессора вообще ничего не может. Это один из нюансов, из-за которых Java/C# обычно серьёзно отстают от нормального C++ кода. И Qt тут действует в лучших традициях Java. Хотя в целом для GUI фреймворка это естественно простительно, т.к. на GUI почти никогда не бывает серьёзной нагрузки и соответственно рассуждать тут об оптимальности — это из области ненужной предварительной оптимизации. Но если говорить о принципах, то это как раз пример того, как не надо делать.
Ну так храните указатели на них, если так принципиально и используйте RAII. Только implicit sharing по сути тоже самое RAII и есть, только реализация от вас спрятана.
К примеру если я загоню в неё данные в виде своего класса, который держит данные в себе и рассчитывает на работу через перемещение.
Ну естественно, если вы передаете в вызове сигнала стековую временную переменную, или явно используете move, то объект передасться через move семантику, т.к. сигнал это по сути просто вызов функции слота в случае Direct Connection. В случае QueuedConnection все тоже самое, только данные будут какое то время хранится и передадутся в слот когда дойдет очередь. Используется ли там move семантика при передаче от сигнала в слот, я не знаю, нужно смотреть исходники.
На самом деле я уже утратил интерес к дискуссии. Мне всегда была интересна мотивация этой распространенной позиции, типа qt только для интерфейсов, особенно когда приходиться разгребать всю эту свалку библиотек от такого подхода (о, как это все еще и компилировать вместе, отдельная, сказочная история) и я не понимал зачем это нужно.
Не понимаю и сейчас, вы признаетесь, что в Qt есть все что нужно, но он вам не удобен. Мне удобен.
Модель акторов — это же естественно не просто какая-то библиотека, а скорее математическое понятие. Причём реализация этой модели может быть крайне простой и не требовать каких-то библиотек (собственно нам требуются только функции вида CreateThread, PostMessage, GetMessage, которые есть в наличие даже просто в WinAPI). Я частенько реализую подобное сам (правда более удобными способами, типа потоков из стандартной библиотеки C++ и т.п.), просто на базе потоков ОС и соответствующих системных очередей сообщений. Ну а в том же языке D модель акторов вообще встроена в сам язык.
Значит Qt сигналы слоты — это вам еще и модель акторов.
Да, кстати, а с появлением в C++ семантики перемещения (между прочим уникальная вещь, которой не видно у других мейнстрим языков) этот метод становится ещё эффективнее. Только вот интересно, Qt про это не в курсе или нет? ) Т.е. модифицирован ли их код передачи данных через очередь так, чтобы избежать лишних копирований? ) Я не разбирался (т.к. использую для многопоточности другие инструменты, а не Qt), но вполне допускаю, что там остался старый неэффективный код.
Всем implicit sharing классам и без мув семантики хорошо живется, а они в Qt практически все такие, которые являются разновидностью данных
Во вторых, с появлением в c++11 и с версии qt 5.0 были добавлены конструкторы копирования с move семантикой, но им это не особо и надо. Смотри доки для QVector например.
Вообще я что-то начинаю подозревать что вы не очень хорошо знакомы с кодом Qt, а так же его внутренней реализацией. Как вы вообще понимаете что в Qt старый неэффективный код?
Нет, не только для многопоточности конечно же. Можете посмотреть мою публикацию для чего например.
Или например Кооперативная многозадачность. Да вообщем все то, для чего нужен libevent. По сути один механизм, полезный и для обмена сообщениями, и для многопоточных приложений и для кооперативной многозадачности без необходимости еще одного профессионального решения. CAF я открыл и закрыл сразу, может быть где не будет Qt я когда нибудь это заюзаю, но куда уж проще для обмена между потоками использовать future и собственную реализацию очереди чем тянуть еще одну крутую библиотеку.
Я говорил скорее о стиле современного C++, в котором царствует статический полиморфизм, RAII, шаблоны, стековые переменные, элементы функционального стиля и т.п. C++11 с его лямбдами, семантикой перемещения и т.п. всего лишь делает этот подход эффективнее, но он работал и до C++11
Кроме статического полиморфизма, все это широко применяется в Qt.
Qt не написана в стиле Java, Qt взяла от туда некоторое количество подходов и паттернов, включая многопоточное программирование.
Что же касается приведение к «Qt типам», то это собственно о чём речь?
Вы к примеру берете какие либо данные с бд, сначала они приводятся к какому то типу самой либы, которая предоставляет доступ к бд, потом вы из этого извлекаете данные которые приводите к своей сущности, ну а по скольку своя сущность ничего про Qt не знает, вы эту сащность каким либо образом натаскиваете чтобы она могла отобразиться в GUI.
А типов много — классы изображений (QImage, QPixmap), QVariant, контейнеры (QList довольно часто используется в виджетах), QByteArray.
Может и так. Только мне не нужно ломать голову над макросами.
Препроцессор мне не мешает. А вот безумно долго компиляющийся буст, и подозреваю какие нибудь крутые макросы, бывает очень мешает.
Я говорил не про стиль кодирования (типа применение с++11 фич), а про способ использования. Какие то либы сами выделяют память и контролируют её, какие то пользуются концепцией RAII, какие то требуют специальных функций для освобождения и создания объектов, какие то не потокобезопасные, какие то наоборот, переусложненные из-за своей безопасности, какие то используют свой асинхронные интерфейс со своим набором коллбэков и правила их задания (потокобезопасность та же, ага). И в конце концов, чтобы общаться с Qt интерфейсом вам весь этот зоопарк типов, коллбеков, менеджеров памяти и прочих с++ крутых вещей нужно приводить к Qt типам и наоборот.
В итоге проект превращается в этакого монстра в котором 80% времени борешься с его очень крутыми фичами и мозголомкой как же мне встроить во все это многообразие новый кусок кода, и только 20% времни тратишь на написание нового функционала.
Проблема в том, что я до сих ищу подтверждения того, что Qt чем то уступает по скорости каким то другим приложениям.
Одна из немногих старых статей которые я нашел хоть с каким то бенчмарком — http://incise.org/hash-table-benchmarks.html, и что интересно, буст там оказался в жестких аутсайдерах.
Ну или вот еще троллинг от самих троллтехов — http://blog.qt.io/blog/2009/08/24/with-or-without-qt/
В итоге получается что если вы уже используете Qt, вы еще дополнительно намешиваете туда солянку из различных либ, которые каждая имеет свои правила использования (один boost чего стоит, абсолютно неоднороден в использовании) и типы, и естественно требуют оверхеда на переконвертацию из одних типов в другие при взаимодействии, при том что в Qt как правило все это уже есть и вы получите однообразный код, который еще, довольно легко встраивать и в многопоточные и событийные паттерны. В вашем же случае, каждая сущность, даже тот же буст в котором этих сущностей очень много, требует своего бережного индивидуального подхода.
Т.е. кросплатформенные технологии как межпроцессное взаимодействие и работа с процессами, работа с БД, кооперативная многозадачность практически из коробки, работа с последовательными портами, bluetooth, nfc, сетью включая клиент серверную логику и websocket, несколько паттернов работы с потоками включая map-reduce и различные примитивы синхронизации включая атомарные, implicit sharing контейнерные классы, работа с файловой системой включая опевещения изменения состояния файла, работа с форматами json, xml, регулярные выражения, unicode строки из коробки, средства для юнит тестирования, средства для встраивания скриптового кода в бинарные программы ну и наконец самые распространенные сигнал слоты заменяющие массу кода реализации их вручную с поддержкой очередей — все это будете тягать не из Qt несмотря на то, что он уже есть у вас в проекте?
Не получается по инструкции запустить GogoleFitResearch. После выбора аккаунта "Неизвестная ошибка с Сервисами Google Play". Проверял на двух разных телефонах. В чем может быть проблема? Приложение подписал ключём, SHA1 которого добавил в свой проект в Google Developer Console. Может быть что то еще нужно сделать?
Во первых, необходимость в этом классе редка и связана она с накладными расходами на выделение динамической памяти, что естественно больше. Я знаю только два случая, когда это становится ощутимой проблемой — в embedded разработке и высоконагруженных приложениях. В первом случае стараются выделить в куче (или в стеке если размер позволяет) память заранее и затем её распределять, например через placement new или просто вручную. Во втором переопределяют операторы new и delete глобально и оптимизируют выделение памяти. Оба этих варианта решают проблему глобально, без допольнительных специальных классов типа std::array или QVarLengthArray. А вот использование стековой памяти неявно где это только возможно чревато проблемами в той же embedded разработке, я полагаю.
Во вторых, исходя из той же документации, это был внутренний класс Qt который они использовали, а значит вполне возможно используется и в контейнерах, и вытащили его на тот случай, если он пригодиться. Мне вот не пригодился ни разу.
Нет, у QVector вместо оператора [], нужно вызывать метод at для извлечения элементов, он напрямую обращается к памяти по указателю. Можете посмотреть исходники QVector и проверить. Это идет в разрез с устоявшемся в stl operator [] и методом at, где смысл примерно наоборот этих методов, но контейнеры qt были когда stl еще не был стандартом.
Эффективнее тем, что память выделяется в стеке, а не в куче? А есть какие нибудь статьи которые сравнивают производительность хранения в этих областях памяти? И вообще, это так принципиально хранить строки крайне производительно?
Просто забудьте как устроен implicit sharing и думайте что в qt move семантика повсеместна. Потому что это практически одно и тоже по производитльности (дайте мне бенчмарки где это опровергается). Я вообще считаю, что move семантика еще один способ выстрелить себе в ногу: — цитата от сюда. Сами создатели стандарта это утверждают.
Есть, свои контролы которые отрисовываются в opengl.
Для строк это еще более менее применимо. Но хранить вектор в стеке — это как вообще? Как это будет вообще работать в embedded, где размер стека часто бывает сильно ограничен?
Я подозреваю, если передаются implicit sharing, то разницы вообще не заметят эти самые программисты. Зато дополнительные трахи с rvalue семантикой очень можно приобрести. Меня поэтому это вообще не заботит, я кстати тоже программист С++, который не брезгует новым стандартом.
Я не вижу где она кривая в упор. Зато неоднократно видел кривость решений где "Qt только для интерфейсов".
Попробуйте openFrameworks. Мне кажется вам понравится.
Любая технология ограничена какими то рамками. И Qt не исключение.
Ну так храните указатели на них, если так принципиально и используйте RAII. Только implicit sharing по сути тоже самое RAII и есть, только реализация от вас спрятана.
Ну естественно, если вы передаете в вызове сигнала стековую временную переменную, или явно используете move, то объект передасться через move семантику, т.к. сигнал это по сути просто вызов функции слота в случае Direct Connection. В случае QueuedConnection все тоже самое, только данные будут какое то время хранится и передадутся в слот когда дойдет очередь. Используется ли там move семантика при передаче от сигнала в слот, я не знаю, нужно смотреть исходники.
На самом деле я уже утратил интерес к дискуссии. Мне всегда была интересна мотивация этой распространенной позиции, типа qt только для интерфейсов, особенно когда приходиться разгребать всю эту свалку библиотек от такого подхода (о, как это все еще и компилировать вместе, отдельная, сказочная история) и я не понимал зачем это нужно.
Не понимаю и сейчас, вы признаетесь, что в Qt есть все что нужно, но он вам не удобен. Мне удобен.
Значит Qt сигналы слоты — это вам еще и модель акторов.
Вообще я что-то начинаю подозревать что вы не очень хорошо знакомы с кодом Qt, а так же его внутренней реализацией. Как вы вообще понимаете что в Qt старый неэффективный код?
Да при том, что это просто еще один способ работы с потоками который никак не противоречит другим способам.
Не важно что путешествует между слоями. Важно какими усилиями вы приводите все к нужному виду.
Или например Кооперативная многозадачность. Да вообщем все то, для чего нужен libevent. По сути один механизм, полезный и для обмена сообщениями, и для многопоточных приложений и для кооперативной многозадачности без необходимости еще одного профессионального решения. CAF я открыл и закрыл сразу, может быть где не будет Qt я когда нибудь это заюзаю, но куда уж проще для обмена между потоками использовать future и собственную реализацию очереди чем тянуть еще одну крутую библиотеку.
Очередей нет, как и в любой другой альтернативной реализации сигналов и слотов
Кроме статического полиморфизма, все это широко применяется в Qt.
Qt не написана в стиле Java, Qt взяла от туда некоторое количество подходов и паттернов, включая многопоточное программирование.
Вы к примеру берете какие либо данные с бд, сначала они приводятся к какому то типу самой либы, которая предоставляет доступ к бд, потом вы из этого извлекаете данные которые приводите к своей сущности, ну а по скольку своя сущность ничего про Qt не знает, вы эту сащность каким либо образом натаскиваете чтобы она могла отобразиться в GUI.
А типов много — классы изображений (QImage, QPixmap), QVariant, контейнеры (QList довольно часто используется в виджетах), QByteArray.
Препроцессор мне не мешает. А вот безумно долго компиляющийся буст, и подозреваю какие нибудь крутые макросы, бывает очень мешает.
В итоге проект превращается в этакого монстра в котором 80% времени борешься с его очень крутыми фичами и мозголомкой как же мне встроить во все это многообразие новый кусок кода, и только 20% времни тратишь на написание нового функционала.
Одна из немногих старых статей которые я нашел хоть с каким то бенчмарком — http://incise.org/hash-table-benchmarks.html, и что интересно, буст там оказался в жестких аутсайдерах.
Ну или вот еще троллинг от самих троллтехов — http://blog.qt.io/blog/2009/08/24/with-or-without-qt/
Зато видел вот такой удивительный пример, когда чувак отказался от Qt QMutex в пользу стандартного и просел в производительности — http://stackoverflow.com/questions/29170495/performance-of-stdmutex-and-qmutex-in-mingw-64-posix-thread-version
Так что вопрос по быстроте программы для меня остается открытым.
А десериализация: