I
Ilya_M6. Juni 2018 16:07

Serialisierung zu und für Qt

Im ersten Teil einer Artikelserie ging der Autor auf die Problematik des Tunings ein und Zusammenführen von Nachrichten und Reduzieren ihrer Last in Telemetriesensoren.

In diesem Teil geht es um Nachrichtennutzlast und deren Optimierung.


Es gibt viele Methoden, um ein Objekt mit Qt zu serialisieren. Im ersten Teil der Artikelserie haben wir JSON verwendet. Dazu werden alle Informationen über den Sensor in QJsonObject gespeichert und QJsonDocument kümmert sich um den Fluss der Werte in QByteArray.

QJsonObject jobject;

jobject[ "SensorID" ] = m_id;
jobject[ "AmbientTemperature" ] = m_ambientTemperature;
jobject[ "ObjectTemperature" ] = m_objectTemperature;
jobject[ "AccelerometerX" ] = m_accelerometerX;
jobject[ "AccelerometerY" ] = m_accelerometerY;
jobject[ "AccelerometerZ" ] = m_accelerometerZ;
jobject[ "Altitude" ] = m_altitude;
jobject[ "Light" ] = m_light;
jobject[ "Humidity" ] = m_humidity;

QJsonDocument doc( jobject );

return doc.toJson();

JSON hat mehrere Vorteile:

  • Text JSON ist beschreibend und für Menschen lesbar;
  • und die Informationen strukturiert sind;
  • der Austausch grundlegender Informationen ist einfach und klar;
  • Mit JSON können Sie Nachrichten mit zusätzlichen Werten erweitern;
  • Es gibt viele Lösungen zum Analysieren und Analysieren von JSON in der Cloud.

Dieser Ansatz hat jedoch einige Einschränkungen. Erstens kann das Erstellen einer JSON-Nachricht ein schwerer Vorgang sein, der viele Zyklen dauert. Der Benchmark des zweiten Teils des Tests zeigt, dass die Serialisierung und Deserialisierung von 10.000 Nachrichten etwa 263 ms dauert. Es mag nicht nach vielen Botschaften klingen, aber in diesem Zusammenhang ist Zeit gleichbedeutend mit Energie. Dies kann den Sensor, der für eine lange Zeit ohne Aufladen ausgelegt ist, erheblich beeinträchtigen.

Ein weiterer Aspekt ist, dass die Nutzlast für die MQTT-Nachricht zur Sensoraktualisierung 346 Bytes beträgt. Da der Sensor nur acht Takes und eine begrenzte Zeile sendet, kann dies ein potenziell großer Rechenaufwand sein.

In den Kommentaren des vorherigen Beitrags wird empfohlen, QJsonDocument : Compact (compact) zu verwenden, wodurch die Größe der Nutzlast im Durchschnitt auf 290 Bytes reduziert wird

Wie kann dies verbessert werden?

Wie die meisten von Ihnen wissen, gibt es auch binäres JSON, das die Lesbarkeit beeinträchtigen kann, aber alle anderen Aspekte sind immer noch relevant. Das Wichtigste beim Ausführen von Benchmarks ist, dass ein einfacher doc.toJson-Schalter in doc.toBinaryData die Geschwindigkeit des Tests verdoppelt und die Benchmark-Iteration auf 125 Millisekunden reduziert.

Nach Überprüfung der Last beträgt die Nachrichtengröße 338 Byte, der Unterschied ist fast nicht wahrnehmbar. Dies kann sich jedoch in verschiedenen Szenarien ändern, beispielsweise wenn weitere Zeilen innerhalb der Nachricht hinzugefügt werden.

Je nach Anforderung können Drittprojekte und andere Features hinzugefügt werden.

Falls das Projekt „innerhalb der Qt-Welt“ ist, ist der gesamte Datenstrom definiert und ändert QDataStream nicht, ist eine mögliche Option.

Wir fügen der SensorInformation-Klasse Unterstützung dafür hinzu, was das Hinzufügen von zwei Anweisungen erfordert.

QDataStream &operator<<(QDataStream &, const SensorInformation &);
QDataStream &operator>>(QDataStream &, SensorInformation &);

Die Implementierung ist recht einfach, unten ist ein Beispiel für die Serialisierung:

QDataStream &operator<<(QDataStream &out, const SensorInformation &item)
{
    QDataStream::FloatingPointPrecision prev = out.floatingPointPrecision();
    out.setFloatingPointPrecision(QDataStream::DoublePrecision);
    out << item.m_id
        << item.m_ambientTemperature
        << item.m_objectTemperature
        << item.m_accelerometerX
        << item.m_accelerometerY
        << item.m_accelerometerZ
        << item.m_altitude
        << item.m_light
        << item.m_humidity;
    out.setFloatingPointPrecision(prev);
    return out;
}

Bei Verwendung von QDataStream betrug die Benchmark-Zeit 26 Millisekunden, was fast 10-mal schneller ist als Text-JSON. Außerdem beträgt die durchschnittliche Nachrichtengröße nur 84 Bytes im Vergleich zu 290. Wenn die oben genannten Grenzen akzeptabel sind, ist QDataStream daher eine gute Option für die anstehende Aufgabe.

Wenn das Projekt das Hinzufügen zusätzlicher Komponenten von Drittanbietern zulässt, ist eine der bekanntesten Serialisierungslösungen das Google Buffer Protocol (protobuf).

Um protobuf zu unserer Lösung hinzuzufügen, müssen wir einige Änderungen vornehmen. Erstens verwendet protobuf IDL, um Datenstrukturen oder Nachrichten zu beschreiben. Dann die Entwicklung des Informationssensors:

syntax = "proto2" ;

package serialtest;

message Sensor {
    required string id = 1;
    required double ambientTemperature = 2;
    required double objectTemperature = 3;
    required double accelerometerX = 4;
    required double accelerometerY = 5;
    required double accelerometerZ = 6;
    required double altitude = 7;
    required double light = 8;
    required double humidity = 9;
}

Um einem qmake-Projekt einen protobuf (Protokoll)-Codegenerator hinzuzufügen, müssen Sie einen zusätzlichen Compiler-Schritt wie diesen hinzufügen:

PROTO_FILE = sensor.proto
protoc.output = $${OUT_PWD}/${QMAKE_FILE_IN_BASE}.pb.cc
protoc.commands = $${PROTO_PATH}/bin/protoc -I=$$relative_path($${PWD}, $${OUT_PWD}) --cpp_out=. ${QMAKE_FILE_NAME}
protoc.variable_out = GENERATED_SOURCES
protoc.input = PROTO_FILE
QMAKE_EXTRA_COMPILERS += protoc

Um dann einen vergleichbaren Benchmark in Bezug auf die Objektgröße zu haben, wird eine generierte Struktur als Mitglied für die SensorInformationProto-Klasse verwendet, die QObject erbt, wie im QDataStream- und JSON-Beispiel

class SensorInformationProto : public QObject
{
    Q_OBJECT
    Q_PROPERTY( double ambientTemperature READ ambientTemperature WRITE 
    setAmbientTemperature NOTIFY ambientTemperatureChanged)
[...]

public :
    SensorInformationProto( const std::string &pr);
[...]

    std::string serialize() const ;
[...]

private :
    serialtest::Sensor m_protoInfo;
};

Die Proto-Info-Serialisierungsfunktion wird vom Protokoll generiert, daher ist der Schritt zum Erstellen der zu übergebenden Nutzdaten wie folgt:

std::string SensorInformationProto::serialize() const
{
    std::string res;
    m_protoInfo.SerializeToString(&res);
    return res;
}

Beachten Sie, dass protobuf im Vergleich zu früheren Lösungen eine STD-Zeichenfolge verwendet. Dies bedeutet, dass Sie die Fähigkeiten von QString verlieren, es sei denn, die Zeichenfolge wird als Byte-Array gespeichert (manuelle Konvertierung erforderlich). Auch dies verlangsamt den gesamten Prozess aufgrund des Parsens.

Aus Performance-Sicht sehen die Benchmark-Ergebnisse vielversprechend aus. Ein Benchmark mit 10.000 Elementen dauert nur 5 ms bei einer durchschnittlichen Nachrichtengröße von 82 Bytes.

Als Fazit zeigt die folgende Tabelle die unterschiedlichen Ansätze zur Serialisierung:

| | Nutzlastgröße | Zeit (ms) |
| json (Text) | 346 | 263 |
| json (binär) | 338 | 125 |
| QDataStream | 84 | 26 |
| Protobuf | 82 | 5 |

Eine vielversprechende Alternative ist CBOR, das derzeit von Thiago Macieira für Qt 5.12 implementiert wird. Da der Entwicklungsprozess jedoch weitergeht, ist es noch zu früh, ihn in diesen Artikel aufzunehmen. Die Ergebnisse der Diskussionen sehen vielversprechend aus, mit einer erheblichen Leistung gegenüber JSON und all seinen Vorteilen.

Der Artikel zeigte verschiedene Ansätze zur Serialisierung von Daten in MQTT-Nachrichtennutzlasten. Dies kann ausschließlich innerhalb von Qt oder mit externen Lösungen (zB protobuf) erfolgen. Die Integration externer Lösungen in Qt ist einfach.

Es ist erwähnenswert, dass alle Serialisierungen, die mit dem Benchmark durchgeführt wurden, mit einer kleinen Datenmenge in der Nachricht durchgeführt wurden, und wenn die Datenmenge größer ist, können die Ergebnisse abweichen und zu unterschiedlichen Ansätzen führen bessere Ergebnisse.

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Stabiles Hosting des sozialen Netzwerks EVILEG. Wir empfehlen VDS-Hosting für Django-Projekte.

Magst du es? In sozialen Netzwerken teilen!

Kommentare

Nur autorisierte Benutzer können Kommentare posten.
Bitte Anmelden oder Registrieren
Letzte Kommentare
ИМ
Игорь Максимов5. Oktober 2024 07:51
Django – Lektion 064. So schreiben Sie eine Python-Markdown-Erweiterung Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas55. Juli 2024 11:02
QML - Lektion 016. SQLite-Datenbank und das Arbeiten damit in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssr8. Februar 2024 18:43
Qt Linux - Lektion 001. Autorun Qt-Anwendung unter Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lektion 007. Arbeiten mit ICMP-Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25. Dezember 2023 10:30
Boost - statisches Verknüpfen im CMake-Projekt unter Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
Jetzt im Forum diskutieren
J
JacobFib17. Oktober 2024 03:27
добавить qlineseries в функции Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты https://topdecorpro.ru…
JW
Jhon Wick1. Oktober 2024 15:52
Indian Food Restaurant In Columbus OH| Layla’s Kitchen Indian Restaurant If you're looking for a truly authentic https://www.laylaskitchenrestaurantohio.com/ , Layla’s Kitchen Indian Restaurant is your go-to destination. Located at 6152 Cleveland Ave, Colu…
КГ
Кирилл Гусарев27. September 2024 09:09
Не запускается программа на Qt: точка входа в процедуру не найдена в библиотеке DLL Написал программу на C++ Qt в Qt Creator, сбилдил Release с помощью MinGW 64-bit, бинарнику напихал dll-ки с помощью windeployqt.exe. При попытке запуска моей сбилженной программы выдаёт три оши…
F
Fynjy22. Juli 2024 04:15
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

Folgen Sie uns in sozialen Netzwerken