Qt: дизайн сигнала / слота и производительность

Я недавно начал использовать Qt, и мне нужно немного разъяснить механизм сигнала / слота. Я понимаю, что это отличный инструмент для графического интерфейса пользователя и связи между объектами, живущими в отдельных потоках, но я не совсем уверен, стоит ли использовать его в простых случаях, подобных следующему.

У меня есть три класса, давайте назовем их MainWindow, DataManager и DataWorker. DataWorker живет в отдельном потоке и сигнализирует, когда новые данные готовы для сбора. Затем он визуализируется в виджетах MainWindow после некоторой обработки. Я создал класс DataManager, чтобы не загрязнять класс GUI обработкой кода.

Теперь, как я должен обрабатывать связь между DataManager и MainWindow.


Вариант №1 — иметь указатель на MainWindow в качестве члена и просто вызывать его метод

class MainWindow
{
private:
DataManager* dm;

public:
MainWindow() : dm(new DataManager(this)) { }
displayData(const char* processedData);
}

class DataManager : QObject
{
private:
MainWindow *mw;

private slots;
eventNewData()
{
// get and process the data
mw = this->QObject.parent();
mw->displayData(const char* processedData);
// release data
}
}

Вариант № 2 — сигнализировать о новых данных для вызова слота MainWindow

class MainWindow
{
private:
DataManager* dm;

private slots:
displayData(const char* processedData);

public:
MainWindow() : dm(new DataManager(this)) { QObject::connect(dm, SIGNAL(newData(const char*)), this, SLOT(displayData(const char*)); }

};

class DataManager : QObject
{
signals:
newData(const char* processedData);

private slots;
eventNewData()
{
// get and process the data
emit newData(processedData);
// release data
}
}

Вариант 1 кажется мне более интуитивным, но опять же я не очень хорошо знаю Qt. Я вижу преимущество использования сигналов и слотов, если будет больше классов, на которые я хотел бы отреагировать на сигнал newData ().

Так что же лучше, и есть ли разница в производительности между ними?

3

Решение

Первый вариант обеспечивает лучшую производительность, чем использование механизма сигнал / слот, но он также имеет недостаток, заключающийся в тесной связи между MainWindow а также DataManager, Оба знают друг друга, поэтому их нельзя использовать отдельно.
Уже одно это должно стать причиной для рефакторинга кода.

Тем не менее, в качестве третьего варианта вы могли бы позволить MainWindow есть слот, который получил сигнал от DataWorker и разреши DataManager быть вспомогательным классом, который просто преобразует данные в пригодный для использования формат для MainWindow,

class MainWindow
{
private:
DataManager* dm;

public:
MainWindow() : dm(new DataManager()) { }
displayData(QString processedData);
private slots;
eventNewData()
{
// get the data
QString processedData = dm->preprocessData(data);
displayData(processedData);
// release data
}
};

class DataManager
{
public:
QString preprocessData(...);
};
3

Другие решения

Вы не можете вызывать функции графического интерфейса непосредственно из вашего потока. Таким образом, опция # 1 не будет работать, если нет соединения сигнал / слот между DataWorker и DataManager :: eventNewData (). Единственный способ вызывать функции графического интерфейса из другого потока — через соединение сигнал / слот.

Связь между сигналами и слотами всегда связана с накладными расходами, поскольку она основана исключительно на времени выполнения и работает со строками (имена слотов генерируются во время компиляции, а затем сравниваются во время выполнения.) Это динамическая диспетчеризация. Прямые вызовы функций всегда быстрее.

Поэтому ответ прост: если вам не нужен сигнал, не используйте его. В данном конкретном случае это не похоже на то, что вам это нужно для связи между DataManager и MainWindow, поскольку все, что вам нужно, это вызвать MainWindow :: displayData (). Не похоже, что вам когда-нибудь понадобится изменить это динамически и вызвать другую функцию. Сигналы и слоты предназначены для обеспечения связи между потоками и соединений, подобных коммутатору. Если вам это не нужно, тогда нет необходимости использовать сигналы.

3

Я не знаю точно, как работает QT, поэтому я не уверен, что производительность падает, но моя интуиция говорит
1. не должно быть большой разницы
2. это, вероятно, не будет иметь никакого значения в контексте GUI.

Опция, использующая стандартный механизм QT, имеет то преимущество, что DataManager не нужно ничего знать о GUI. Многие люди считают этот хороший дизайн, потому что он может позволить вам заменить ваш графический интерфейс без изменений во внутренних органах.

0
По вопросам рекламы [email protected]