Russian Qt Forum
Ноябрь 22, 2024, 23:47 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Система сигнал/слот работает медленно?  (Прочитано 6318 раз)
padevong
Гость
« : Апрель 05, 2010, 06:45 »

CPU x86 800 Мгц. ОС - xlinux. Qt embedded 4.5.3.
Есть необходимость общаться с внешними устройствами через интервалы порядка 1 мс.
Данные будут формироваться в одном потоке, затем отдаваться одному или двум другим, которые уже непосредственно общаются с внешними устройствами  (дизайн условный, сделан для проверки возможностей проца, операционки и qt).
Обнаружил, что если передавать сообщения от первого потока с помощью системы сигнал/слот то загрузка процессора очень высокая (если отдавать сообщения одному потоку то ~1%, если двум то ~85%). Если же вместо системы сигнал/слот использовать семафоры то загрузка проца близка к 0.

Для проверки сделал два примера:

1.Пример 1
Первый поток спит 1 мс и затем шлет сигнал который связан со слотами задач выдающих данные в порт.
Код
C++ (Qt)
void Data::run() {
   forever {
       usleep(1000);
       emit timeoutSignal();
   }
}
 
В потоке общающемся с внешним устройством (таких потока один или два) просто запускается цикл обработки сообщений и описан слот:
Код
C++ (Qt)
void Port::run() {
   exec();
}
void Port::timoutSlot() {
   write_data_to_port();
}
 
Сигналы/слоты связаны так:
Код
C++ (Qt)
int main(int argc, char *argv[])
{
   QApplication a(argc, argv);
   Data *data = new Data();
   Port *port1 = new Port(1);
   Port *port2 = new Port(2);
   QObject::connect(data, SIGNAL(timeoutSignal()), port1, SLOT(timeoutSlot()));
   QObject::connect(data, SIGNAL(timeoutSignal()), port2, SLOT(timeoutSlot()));
   port1->start();
   port2->start();
   port1->moveToThread(port1);
   port2->moveToThread(port2);
   data->start();
   return a.exec();
   data->quit();
   port1->quit();
   port2->quit();
}
 

2.Пример 2
Первый поток спит 1 мс и затем шлет семафор.
Код
C++ (Qt)
void Data::run() {
   forever {
       usleep(1000);
       sem_post(sem);
   }
}
 
Второй поток (их один или два) ждет семафор и пишет в порт:
Код
C++ (Qt)
void Port::run() {
   forever {
       sem_wait(sem);
       write_data_to_port();
   }
}
 

В первом примере загрузка проца ~85%, во втором близка к нулю. Оба варианта работают, данные передаются.
Все сигналы/слоты в первом примере выполняются в своих потоках - проверял.
Действительно ли система сигнал/слот настолько медленно работает или я что-то делаю не так?
Хотелось бы использовать сигналы/слоты поскольку в реальном приложении одному потоку потребуется обрабатывать разные сообщения от нескольких потоков и нельзя просто ждать один семафор. А проверять пришли ли сообщения в цикле не хочется.

« Последнее редактирование: Апрель 05, 2010, 18:56 от padevong » Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #1 : Апрель 05, 2010, 07:24 »

>>Действительно ли система сигнал/слот настолько медленно работает или я что-то делаю не так?
Цитировать
На i586-500 вы можете генерировать около 2,000,000 сигналов, связанных с одним слотом, в секунду, или около 1,200,000 сигналов, связанных с двумя слотами, в секунду. Простой и гибкий механизм сигналов и слотов является хорошей оболочкой для внутренней реализации, которую пользователи даже не будут замечать.
тыц
Записан

Юра.
mkv
Гость
« Ответ #2 : Апрель 05, 2010, 08:34 »

to lit-uriy
можете выложить полный исходник теста?
тоже интересует этот вопрос...
наверное дело в том, что сигнал проходит  границу между потоками и тут есть еще больший оверхед.
Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #3 : Апрель 05, 2010, 12:34 »

>>можете выложить полный исходник теста?
гдеж я его возьму? Я дал ссылку на то место в документации, где я взял эту цитату.
Записан

Юра.
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Апрель 05, 2010, 13:49 »

Надо почистить оба примера, потом смотреть скорость. В 1-м случае connect происходит с DirectConnection, то что потом сделано moveToThread - не роялит. Значит 2 write_data_to_port  будут выполняться последовательно в главной нитке.
Лучше напр. сделать connect в начале Port::run с флагом QueuedConnection. Во 2-м примере семафор сработает верно  (приятнее использовать QSemaphore вместо sem_) но только 1 раз, дальше Data::run заканчивается.
Записан
padevong
Гость
« Ответ #5 : Апрель 05, 2010, 18:48 »

Надо почистить оба примера, потом смотреть скорость. В 1-м случае connect происходит с DirectConnection, то что потом сделано moveToThread - не роялит. Значит 2 write_data_to_port  будут выполняться последовательно в главной нитке.
Лучше напр. сделать connect в начале Port::run с флагом QueuedConnection.
Каждый write_data_to_port() выполняется не в главной нитке, а в контексте своего потока - проверял (выводил id потока в этой функции).

Во 2-м примере семафор сработает верно  (приятнее использовать QSemaphore вместо sem_) но только 1 раз, дальше Data::run заканчивается.
Верно подмечено, но на самом деле в функции run() есть цикл forever, я просто неправильно запостил пример.

Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Апрель 05, 2010, 19:43 »

Каждый write_data_to_port() выполняется не в главной нитке, а в контексте своего потока - проверял (выводил id потока в этой функции).
Это должно быть не так судя по приведенному Вами тексту. Выложите минимальный проект, если нет возможности - покажите как проверяете.  

Edit: также forever не решает проблемы - на каждый оборот цикла только 1 из 2-х Port сработает, который - случайно/невоспроизводимо
« Последнее редактирование: Апрель 05, 2010, 22:20 от Igors » Записан
padevong
Гость
« Ответ #7 : Апрель 06, 2010, 12:23 »

Протестив всё вдоль и поперёк выяснил, что проблема была в том что запускалась прога удаленно с
ключом -display VNC:0, который я использовал для того чтобы подключаться через vnc и смотреть ui.
Напомню, что это был qt embedded и прога для промышленного контроллера.
При таком способе запуска загрузка проца высокая:
exchange_test -qws -display VNC:0
А если запускать так:
exchange_test -qws
то загрузка проца близка к 0.
Еще остались вопросы, например, почему, при использовании ключа -display VNC:0,
загрузка проца так сильно зависит от количества задач ждущих сигнала (если одна то 1%,
а если две то уже 80-85%) или почему загрузки проца нет в случае с семафорами.
Но факт имеется.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.219 секунд. Запросов: 22.