Russian Qt Forum

Qt => Многопоточное программирование, процессы => Тема начата: rudireg от Октябрь 22, 2016, 19:10



Название: Как организовать многопоточность? Выбор модели
Отправлено: rudireg от Октябрь 22, 2016, 19:10
Привет. Я новичек в Qt  и хотелось бы получить совет.

Задача написать многопоточное приложение.
Приложение для работы с социальной сетью инстаграм.
Например загрузили в программу 200 аккаунтов, дали задачу этим аккаунтам, и далее каждый аккаунт выполняет свою задачу в своем отдельном потоке.

Я вижу три типа потоков в программе:
1) Есть главный поток UI  (он отвечает за работу с интерфейсом)
2) Главный UI поток создает дочерний поток, назовем его MASTER (он служит для создания дочерних потоков и управления мим , которые уже ведут работу с аккаунтами)
    MASTER  выдает дочерним потокам задачи и принимает от них сигналы, а так же отвечает за вывод информации в UI
3) Потоки WORKER - они создаются MASTER-ом и им контролируются.

В итоге получаем картину, UI поток создает MASTER поток, далее MASTER  создает WORKER потоки (их может быть много...)

ВОПРОС: Какую модель реализации многопоточности выбрать?
QtConcurrent - тут не подойдет.
Наследоваться от QThread - нет желания.
 Смотрел в сторону QThreadPool - но не знаю подойдет ли оно... ибо если аккаунтов 100, то повзволит ли он пустить 100 потоков.
изначально хотел просто создать в MASTER потоке локальную переменную QList<QThread*> stack; для хранения потоков....

Тут нюанс вот в чем, аккаунтов много, каждый аккаунт в своем потоке... НО.... есть нюанс... потоки не работают на износ, он сделал свою задачу и должен заснуть на минуту и снова сделать свою задачу, и все это дело зациклить... покуда либо не завершится задача, либо поток MASTER  его не остановит принудительно

Как бы вы организовали модель многопоточности?


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: Old от Октябрь 22, 2016, 19:29
Нет никакой необходимости заводить 100 потоков - это разбазаривание ресурсов процессора.
Достаточно пула потоков (количество воркеров в нем можно подбирать в зависимости от, например, количества обслуживаемых аккаунтов) и очереди заданий. Задания в очередь может помещать хоть GUI-поток, хоть MASTER-поток. Воркеры достают задания из очереди и выполняют.
Для этого подойдет и QThread, и QtConcurrent с QThreadPool.


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: Old от Октябрь 22, 2016, 20:01
А если все задачи сводятся к отправке сетевых запросов и получению ответов, то можно вообще без потоков обойтись. Весь сетевой обмен в Qt может работать асинхронно.


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: Bepec от Октябрь 22, 2016, 20:03
Пользователю можно написать, что там 200 потоков, но спокойно работать будут и два. Один на приём, второй на обработку.


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: Old от Октябрь 22, 2016, 20:05
Пользователю можно написать, что там 200 потоков
Зачем?  ::)


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: rudireg от Октябрь 22, 2016, 20:27
Спасибо. Почитаю про QThreadPool, попробую его в реализации...
Буду набираться опыта.

Конечно... сетевые запросы отправляются... и принимаются. Так же полученные пакеты обрабатываются для получения данных...
плюс идет обработка этих данных в SQLite базе... (Наверное каждый поток будет отдельно обращаться к базе через Мютексы)
Каждый аккаунт должен быть отображен в UI - (а именно в QTableWidget)  с информацией о ходе выполнения операции...
в любой момент поток по желанию пользователя может  останавливаться и запускаться снова...
И разнообразие Задач выполняющиеся в WORKER может быть большое множество - их указывает пользователь перед стартом потока WORKER

Например вы писали, что поток Worker берет задание из стека заданий и выполняет его.
А если допустим стоит задание лайкать фотографии по списку пользователей.... с паузой в 50 секунд... (то есть каждые 50 секунд отправляется сетевой запрос) то как бы вы организовали стек задач?
Например: Каждый Worker имеет свой стек задач (хотя можно сделать общий для всех Workerов), и каждые 50 секунд MASTER отправляет в стек  новое задание ( например лайкнуть)...
Или же лучше сразу передать весь список пользователей (тех кого нужно лайкнуть) и указать задержку 50 секунд...
Я к тому, что если я передам WORKERу  сразу всех пользователей (например 1000) и задам паузу (50 секунд), то выполнение задачи в потоке будет выполнятся продолжительное время...
тоесть там будет sleep(50 секунд)  -  не повлияет ли это на загруженность работы QThreadPool?
Не будет ли QThreadPool думать что поток еще выполняет свое задание даже если там пауза... и потому другие потоки будут ожидать его выполнения... хотя он просто стоит на паузе


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: Old от Октябрь 22, 2016, 20:46
Например вы писали, что поток Worker берет задание из стека заданий и выполняет его.
А если допустим стоит задание лайкать фотографии по списку пользователей.... с паузой в 50 секунд... (то есть каждые 50 секунд отправляется сетевой запрос) то как бы вы организовали стек задач?
IMHO, тут архитектурно нужно разделить понятия задачи и операции. Задача это набор операций, выполняемых по заданному алгоритму. Задача хранит список пользователей и другие необходимые параметры, и по таймеру в 50 сек ставит в очередь операцию - лайкнуть фотографию.
Вот для операций, как раз подойдет пул потоков. Все задачи ставят в его очередь необходимые для выполнения операции, а воркеры пула по мере возможности их выполняют.
Поищите, на сайте были темы про очереди заданий с примерами кода.



Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: Igors от Октябрь 23, 2016, 08:23
.. покуда либо не завершится задача, либо поток MASTER  его не остановит принудительно
Нет такой легкой/удобной возможности "остановить принудительно"

Как бы вы организовали модель многопоточности?
Она давно известна. Запускается столько ниток сколько ядер и им скармливаются задачи. Нужно стремиться к тому чтобы любая задача могла быть отдана любой нитке на выполнение. Многочисленные попытки решить проблемы созданием бОльшего числа ниток (обычно закрепляя за ниткой какую-то конкретную задачу - так кажется удобнее) никогда ничего хорошего не давали.

Цитировать
А если вот длинная задача - ну не могу же я ждать ее завершения, если у меня появилась др задача которую надо сделать как можно быстрее
Значит надо нарезать длинную на более мелкие, в этом обычно работа и состоит (да, это часто непросто)


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: rudireg от Октябрь 23, 2016, 13:36
Интересный принцип работы QTreadPool.  :D

Псевдокод
Код
C++ (Qt)
Worker* worker = new Worker;  // Inherit QRunnable
 
QThreadPool *threadPool = new QThreadPool;
 
for(int i=0; i < 20; i++) {
       if(!threadPool->globalInstance()->tryStart(worker))
           qDebug() << i << " tryStart = false";
       else
           qDebug() << i << " tryStart = true";
       };
 

Так можно проверить какое количество ниток QThreaPool резервирует для работы...
В моем случае  QThreaPool зарезервировало 8 ниток.
У меня процессор имеет 4 ядра (плюс каждое ядро разделено на 2 виртуальных) итого 8 ядер.


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: Old от Октябрь 23, 2016, 13:45
int   QThreadPool::activeThreadCount() const

int   QThreadPool::maxThreadCount() const
void   QThreadPool::setMaxThreadCount(int maxThreadCount)

int QThread::idealThreadCount()


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: rudireg от Октябрь 23, 2016, 15:04
Решил попробывать получить количество активных ниток в пуле
int   QThreadPool::activeThreadCount() const

Запускаю проверку активных потоков до и после резервирования ниток
Код
C++ (Qt)
Worker* worker = new Worker;  // Inherit QRunnable
QThreadPool *threadPool = new QThreadPool;
 
qDebug() << "activeThreadCount: " << threadPool->activeThreadCount();
 
for(int i=0; i < 20; i++)
       threadPool->globalInstance()->tryStart(worker);
 
qDebug() << "activeThreadCount: " << threadPool->activeThreadCount();
 

В итоге  и ДО и ПОСЛЕ получаю значение 0

в Worker выполняется этот код
Код
C++ (Qt)
void Worker::run()
{
       QThread::sleep(10); // Pause 10 sec
}
 

Почему получаю 0 ? Ведь там есть потоки в работе...


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: Old от Октябрь 23, 2016, 15:56
activeThreadCount показывает количество резервированных потоков.


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: rudireg от Октябрь 23, 2016, 17:33
activeThreadCount показывает количество резервированных потоков.
Да, действительно, следует зарезервировать потоки, лишь после этого мы увидим кол. зарезервированных потоков.
Код
C++ (Qt)
QThreadPool* threadPool = new QThreadPool;
 
threadPool->reserveThread();
threadPool->reserveThread();
threadPool->reserveThread();
 
qDebug() << "Active Threads: " << threadPool->activeThreadCount(); //Will show active Threads
 
 


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: rudireg от Октябрь 24, 2016, 09:28
Выскажите ваше мнение... по поводу того, что в интернете очень часто можно встретить программы, в которых можно указать кол. потоков для работы.
Например вот
(http://okdroid.ru/pic/33.png)

На скриншоте интерфейса программы указано кол. потоков 50 штук.
Я так понимаю что ОС не запускает на самом деле 50 потоков, а создает псевдо потоки.... (видимо они стоят в очереди на выполнение)
Допустим аппаратная мощность компьютера ограничивается 2 ядрами.
Выходит что на самом деле используется 2 потока а не 50 в итоге...

Я думаю указание 50 потоков в подобных программах скорее для упрощения реализации логики работы программы, обмена данными между псевдо-нитками и главным потоком
ведь тогда ненужно делать допустим очереди заданий, каждому псевдо-потоку соответсвено назначается свое индивидуальное задание.
??? На ваш взгляд какие есть минусы в таком подходе с точки зрения аппаратного использования вычислительных мощностей компьютера?
Почему именно этот метод получил такое широкое распространение в народе...


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: Old от Октябрь 24, 2016, 09:38
Выходит что на самом деле используется 2 потока а не 50 в итоге...
Да можно запустить и 100 потоков, только проку от них никакого не будет.
А разработчику, как вы заметили, так было проще реализовать.


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: deMax от Октябрь 24, 2016, 09:54
Выходит что на самом деле используется 2 потока а не 50 в итоге...
Да хоть сто создайте, зачем только если вычислений с гулькин нос и все потоки простаивают, т.к. считать им нечего. У вас же не сотни тысяч клиентов. Как правило если тяжелые вычисления количество потоков =количеству ядер + по отдельному потоку на гуи/бд/файловую систему и прочие тормозные вещи.


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: Bepec от Октябрь 24, 2016, 10:01
Потоки эт как холопы.
Можно хоть тыщу нагнать, но если надо 2 кирпича с место на место переносить, то двое прекрасно справятся :D
Вот когда двое не будут справляться с нагрузкой - тогда надо добавлять.

Зависимость скорости работы от количества потоков непропорциональная и разнится от задачи к задаче. Но сейчас модно пихать многопоточность всюду, начиная от калькуляторов, заканчивая играми.


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: Igors от Октябрь 24, 2016, 13:31
Выскажите ваше мнение... по поводу того, что в интернете очень часто можно встретить программы, в которых можно указать кол. потоков для работы.
Например вот
Ну это скорее "анти-пример"  :)

Я так понимаю что ОС не запускает на самом деле 50 потоков, а создает псевдо потоки.... (видимо они стоят в очереди на выполнение)
Нет, хоть с 1 ядром ОС честно запускает все 50 (или сколько сказали), каждому выделяется квант времени, гарантируется что нитка получит управление не позже чем <конкретное время>

Почему именно этот метод получил такое широкое распространение в народе...
Просто потому что дятлов всегда больше чем умных :) Оно ж ведь кажется очень удобным - эта нитка занимается одной задачей, другая другой.  


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: rudireg от Октябрь 24, 2016, 17:48
1) Правильно ли я понял тот факт, что запуская объект obj (наследник от QRunnable) на выполнение через QThreadPool,
то есть выполнив команду: QThreadPool::globalInstance()->start(obj);

То метод run() объекта obj выполняется в отдельной нитке и при этом не имеет цикла обработки событий, иными словами obj завершает свою работу как только void run() выполнил последнюю команду.

2) А если нужно что бы нитки не завершали свою работу а просматривали очередь заданий, и если там есть новые задания то брали их на выполнение, а если нет заданий то  нитка засыпает на короткое время (sleep на 1 секунду) и после снова проверяет наличие новых заданий.

Цикл ожидания (сон, и проверка новых заданий) следует реализовать своими силами тогда... верно?
Например зациклить выполнение метода run(), и опрашивать раз в секунду есть ли новое задание на выполнение... если нету, то QThread::sleep(1); и снова проверить очередь.

ВОПРОС:
В правильном ли направлении я мыслю? что бы не вызывать каждый раз QThreadPool::globalInstance()->tryStart(obj)





Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: Old от Октябрь 24, 2016, 18:10
1) Правильно ли я понял тот факт.
Да

2) А если нужно что бы нитки не завершали свою работу а просматривали очередь заданий, и если там есть новые задания то брали их на выполнение, а если нет заданий то  нитка засыпает на короткое время (sleep на 1 секунду) и после снова проверяет наличие новых заданий.
Не нужно так делать - это плохое решение. Для организации таких очередей нужно использовать условные переменные (QWaitCondition).

Цикл ожидания (сон, и проверка новых заданий) следует реализовать своими силами тогда... верно?
Нет, это все уже реализовано в QThreadPool, попробуйте просто добавлять задачи через start, они ставятся в очередь и будут выполняться по мере освобождения воркеров.


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: Igors от Октябрь 25, 2016, 07:03
То метод run() объекта obj выполняется в отдельной нитке и при этом не имеет цикла обработки событий,
Да

иными словами obj завершает свою работу как только void run() выполнил последнюю команду.
Неясно что obj должен "завершать" ???

2) А если нужно что бы нитки не завершали свою работу а просматривали очередь заданий, и если там есть новые задания то брали их на выполнение, а если нет заданий то  нитка засыпает на короткое время (sleep на 1 секунду) и после снова проверяет наличие новых заданий.
Рано или поздно все приходят к одному: sleep хорош для отладки, но НИКОГДА в рабочем коде

Цикл ожидания (сон, и проверка новых заданий) следует реализовать своими силами тогда... верно?
Например зациклить выполнение метода run(), и опрашивать раз в секунду есть ли новое задание на выполнение... если нету, то QThread::sleep(1); и снова проверить очередь.
Это не запрещено, но зачем брать на себя низкоуровневую работу? Гораздо удобнее сидеть в QThread::exec и делать задание при получении сигнала

ВОПРОС:
В правильном ли направлении я мыслю? что бы не вызывать каждый раз QThreadPool::globalInstance()->tryStart(obj)
Не знаю. Ну а что такого уж плохого в QThreadPool и tryStart чтобы его избегать? Подбрасываете ему дровишки-задачки, оформить run несложно. Голова не болит какая нитка чем занимается. Минусы - пожалуй один, нельзя послать obj сигнал, он не в событийном цикле. 


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: rudireg от Октябрь 25, 2016, 15:09
Спасибо вам Old и Igors
Понемногу начинаю разбираться... делаю тесты и выяснил следующее
Методы запуска start и tryStart класса QThreadPool имеют различия:

QThreadPool::start(); - Запускает объект унаследованный от QRunnable на выполнение.
                                          Если нет свободных зарезервированных ниток, то выполнение ставиться в очередь заданий.

QThreadPool::tryStart(); - Пытается запустить объект унаследованный от QRunnable на выполнение.
                                         Если нет свободных зарезервированных ниток, то выполнение НЕ ставиться в очередь заданий, и запуск игнорируется.

И в свою очередь метод QThreadPool::globalInstance()->waitForDone(); - Вызывает ожидание выполнения всех ниток,
                                а после удаляет объекты унаследованные от QRunnable , при условии что объект имеет статус setAutoDelete(true)


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: popper от Октябрь 26, 2016, 18:00
Достаточно подробно про потоки в Qt написано здесь:
Mark Summerfield
Advanced Qt Programming


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: rudireg от Октябрь 27, 2016, 17:49
Возник вопрос.
Допустим задача программы это: отсылка сетевых запросов, получение ответа и их дальнейшая обработка (сохранение coockie, парсинг нужной информации... сохранение информации).
Сетевых запросов много... при этом используются прокси, прокси могут быть медленными... то есть ожидание ответа от сервера может ожидаться например 30 секунд и более (если прокси медленный).

Если программа многопоточная, то поток получив задание сделать сетевой запрос делает следующее:
1) Посылает запрос на сервер
2) Ожидает ответ сервера
3) Получает ответ сервера и обрабатывает его с последующим сохранением нужных данных

И если например таких запросов нужно отправить 1000 штук, а в микропроцессоре компьютера всего 4 ядра,
то получается что в один момент времени программа может работать с максимум 4-мя потоками.
Как можно оптимизировать механизм отправки и получения сетевых запросов? ведь поток ожидая ответа (если прокси медленный).... простаивает.

Ранее я уже не один раз работал в программах с сетевыми запросами, и был написан класс по отправке и приему данных
видимо пришло время его переписать, так как поток будет ожидать ответа от сервера и простаивать...

На всякий случай выкладываю исходники класса по работе с HTTP запросами
rhttp.h
http://codepad.org/VszY9dsj

rhttp.cpp
http://codepad.org/c7fH60ui

На мой вгляд, следует отправлять запрос серверу... и на этом поток завершил свою задачу...
QNetworkReply *reply = this->manager->get(request);


Далее как то нужно сохранить данные об отправке, и на сигнале finished о том что ответ пришел, снова в потоке (в любом) уже принимать ответ от сервера.
QObject::connect(reply, SIGNAL(finished()), какойто объект, SLOT(Слот Обработки ответа сервера()));

Вопрос тока, кто будет этот сигнал посылать, если поток уже отработал и уничтожился, если тока как вариант сохранять reply  в поток MANAGER (главный поток)


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: Bepec от Октябрь 27, 2016, 18:13
Вы НИЧЕРТА не понимаете что такое ядро, что такое поток и что такое ОС :D

Прошу вас - не придумывайте свои понятия.
Ядро - по сути процессор, выполняющий команды.
ОС - программа, позволяющая пользователю работать с компьютером.
Поток - это абстрактный список команд, имеющий право на часть процессорного времени.

Ядро - одно.
Ос - одна.
Потоков - сколько душе угодно. Правда есть предел потоков для ОС, но он чрезвычайно труднодостижим.
Количество потоков ни как не зависит от количества ядер.


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: Old от Октябрь 27, 2016, 18:36
На мой вгляд, следует отправлять запрос серверу...
Не мудрите зря. :)
Пусть будет поток, который отправляет запросы и обрабатывает сигнал:
void QNetworkAccessManager::finished(QNetworkReply *reply)

Заметьте, это сигнал у самого менеждера и в параметре он передает указатель на reply.
Как только, ответ получен - он отправляется на обработку одному из воркеров пула потоков.
Одного потока-менеджера хватит и отправлять запросы (тысячами) и получать ответы, а обработкой будет заниматься потоки из пула.


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: rudireg от Октябрь 27, 2016, 19:20
На мой вгляд, следует отправлять запрос серверу...
Не мудрите зря. :)
Пусть будет поток, который отправляет запросы и обрабатывает сигнал:
void QNetworkAccessManager::finished(QNetworkReply *reply)

Заметьте, это сигнал у самого менеждера и в параметре он передает указатель на reply.
Как только, ответ получен - он отправляется на обработку одному из воркеров пула потоков.
Одного потока-менеджера хватит и отправлять запросы (тысячами) и получать ответы, а обработкой будет заниматься потоки из пула.

Получается такая сехама (поправте меня если я не прав):
1) Есть пул потоков вокеров (QThreadPool)
  (В этих нитках формируются сетевые запросы, например GET запрос http://mail.ru)

2) Есть 1 поток-менеджер, который отвечает за работу с посылкой и приемом сетевых запросов.
    (Имено в нем идет работа с QNetworkAccessManager)

Если я правильно понял схему, то потоки-вокеры  кидают сетевые запросы потоку-менеджеру (кидают через очередь наверное)
   


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: Old от Октябрь 27, 2016, 19:32
Поток-менеджер сам отправляет запросы и сам получает ответы, а вот обработка ответов может выполняться в несколько потоков.
Нет смысла параллелить отправку запросов, все равно все сведется к сетевому стеку ядра, который последовательно их отправит в сеть. И ждать ответа в нескольких потоках тоже нет смысла, с этим справиться и один поток, а вот когда ответ пришел и его нужно долго обрабатывать, то пригодятся отдельные потоки.


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: rudireg от Октябрь 27, 2016, 20:39
Нарисовал схему
Верно ли я понял?

(http://images.vfl.ru/ii/1477590022/dca87575/14701545.jpg)


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: Old от Октябрь 27, 2016, 20:52
В одном потоке живет объект QNetworkAccessManagerа, через него отправляются 1000 запросов, дальше он начинает ждать ответы... Вот пришел первый ответ - отдали его на обработку воркеру, пришел второй ответ - еще одному воркеру, и т.д.
Нет нужды отправлять запросы и пулить ответы в нескольких потоках, ждать легко может только один поток - дело не хитрое. :)


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: rudireg от Октябрь 27, 2016, 22:03
В одном потоке живет объект QNetworkAccessManagerа, через него отправляются 1000 запросов, дальше он начинает ждать ответы... Вот пришел первый ответ - отдали его на обработку воркеру, пришел второй ответ - еще одному воркеру, и т.д.
Нет нужды отправлять запросы и пулить ответы в нескольких потоках, ждать легко может только один поток - дело не хитрое. :)

В общем:
1) Workerформирует URL по которому следует перейти и передает его (URL) менеджеру.
2) Менеджер имея в себе объект QNetworkAccessManager получив URL делает запрос в интернет.
   Далее срабатывает сигнал void QNetworkAccessManager::finished(QNetworkReply *reply)
   который запускает СЛОТ.  Слот который будет вызван где расположить??? В менеджере или в Вокере??
   Думаю что в менеджере наверное.
Видимо не совсем понимаю как отдать ответ вокеру...
    


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: rudireg от Октябрь 28, 2016, 00:38
И каким образом  объект QNetworkAccessManager работающий в отдельном потоке принимает запросы (URL) от вокеров? Через очередь делать?


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: Igors от Октябрь 28, 2016, 07:07
И каким образом  объект QNetworkAccessManager работающий в отдельном потоке принимает запросы (URL) от вокеров? Через очередь делать?
Может не стоит ударяться в специфику (QNetworkAccessManager, URL и.т.п.). Суть та же и без нее. Основной способ взаимодействия  - просто посылка сигнала связанного как QueuedConnection или AutoConnection. Параметры этого сигнала автоматычно заносятся в EventLoop получателя, и когда он выйдет в событийный цикл (exec) он получит этот сигнал. Поэтому не надо городить своих очередей.


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: Old от Октябрь 28, 2016, 07:42
Видимо не совсем понимаю как отдать ответ вокеру...
Многопоточность нужно добавлять тогда, когда она нужна. :)
Для отправки последовательно раз в секунду тысячи запросов и ожидания ответов не нужны потоки. Qt умеет отправлять такие запросы и получать на них ответ асинхронно, не блокируя GUI. Все это легко можно сделать в одном GUI-потоке.
А вот если, например, нужна долгая обработка ответов - то потоки пригодятся. Вот вы описали задачу, один раз в секунду лайкать фотографию от имени одного из 1000 аккаунтов - это легко сделать без всяких потоков.
В общем, нужны детали. Не стоит тянуть многопоточность, только для того что-бы она была. В чем вы видите необходимость параллельной обработки, что будет по вашему долго обрабатываться?


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: rudireg от Октябрь 28, 2016, 14:09
Да вы правы... следует четко определится с точной постановкой задачи, видимо я чего-то недопонимаю.

Имеются следующие задачи:
Программа работает с неограниченным кол. аккаунтов сети Инстаграм.

1) Программа загружает в себя список аккаунтов инстаграм

2) Далее, пользователь выбирает из загруженного списка аккаунтов те аккаунты, с которыми он хочет работать, например выбрал 100 штук,  и каждому аккаунту назначает индивидуальное задание
   Задание может состоять из нескольких операций.
   Пример операций:
   а) Авторизоваться
   б) Сделать лайки
   в) Подписаться
   г) Сделать комментарий.
   и т.д.

3) Допустим мы выбрали 100 наших аккаунтов для работы и назначили каждому аккаунту задание, состоящее из следующих операций:
    а) Авторизоваться
    б) Сделать лайки по списку пользователей (то есть каждый наш аккаунт лайкает пользователей из подготовленного списка)
    в) Сделать комментарий под фото

4) Для работы со списком пользователей которых мы должны лайкнуть (либо написать комментарий), программа имеет базу игнор листов пользователей (реализованы в виде таблиц SQLite). Это что бы не повторятся в лайках. Если мы уже ранее лайкали пользователя, нет нужды второй раз его лайкать, вот для этого в программе есть игнор-листы.
Получается, что перед лайком пользователя, нужно проверить есть ли он в игнор листе, если нету, то лайкаем, а после лайка занести в игнор базу.
Базы могут быть большими, могут быть общими для всех наших аккаунтов, либо сугубо индивидуальными для каждого нашего аккаунта.

Процесс проверки и вставки пользователя в игнор-базу, я бы хотел вынести в отдельный поток WORKER- ибо считаю это нагруженной операцией,
к тому же в будущем могут прибавиться еще проверки...
так же идет работа с логом выполнения работы каждого аккаунта...

Отсупление.......
Отправка сетевых пакетов и их прием делается посредством QNetworkAccessManager в одном отдельном потоке, назовем его MANAGER (который имеет EventLoop)
Поставить в очередь MANAGERу сетевой запрос на выполнение не сложно, через сигналы и слоты WORKER вызывает emit doTask(Объект с данными);
В итоге в очередь MANAGERа на выполнение поступает объект содержащий в себе различные данные: cookie, URL для перехода и другие.
И что происходит дальше? Что дальше делает WORKER? WORKER блокируется и ждет ответа либо лучше его завершить?
Я хочу использовать QThreadPool для коллекции потоков, и пока не понятно сколько он может максимум иметь потоков в работе (не считая тех  потоков что в очереди на выполнение)
Просто какой смысл блокировать WORKER и ждать? проще завершить что бы поток WORKER даром не тратил зарезервированное место в QThreadPool ... но тогда как аккаунту от имени которого выслан запрос серверу - узнать ответ сервера?  Как ответ сервера поместить в структуру аккаунта?
Хотелось бы в структуре каждого аккаунта иметь QByteArray который будет заполнятся ответом сервера, тогда WORKERу при повторной обработке аккаунта будет понятен исход прошлых действий.
Как сохранить ответ сервера  именно в структуре того аккаунта, от имени которого был послан запрос серверу? У нас ведь не 1 аккаунт а 100 штук.
В MANAGER для работы с сетью используется сигнал QNetworkAccessManager::finished(QNetworkReply* reply)
который соединен на слот приема ответа closeRequest(QNetworkReply*)
Слот принимает как параметр объект QNetworkReply* - который содержит ответ... но в слоте нет данных о том, какому аккаунту эти данные принадлежат... ведь у нас их 100 штук...
Вот и думаю как узнать какому аккаунту адресован ответ.

Схему прилагаю. Где:
Синие стрелки — содание потока.
Желтые стрелки — вызов сигнала emit
(http://images.vfl.ru/ii/1477662099/8207d36f/14711380.jpg)
  


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: rudireg от Октябрь 28, 2016, 21:15
Я придумал как отдать ответ сервера нужному аккаунту.... низнаю насколько это будет верным.
1) MASTER  перед тем как передать задание WORKERу инициализирует задание уникальным ID номером  и сохраняет задание  и ID  в QHash<Уникальный ID, Задание>
2) Далее задание поступает WORKERу, где уже пройдя через логические ветвления получает нужный ему URL для перехода по сетевому запросу
3) Теперь когда задание имеет уникальный ID  и нужный ему URL, задание попадает в сетевой поток MANAGER, в котором так же есть хэш заданий QHash<Уникальный ID, Задание>
Далее MANAGER выполняет команду QNetworkReply* reply = this->m_manager->get(request);
мы получаем объект QNetworkReply* reply , и назначем ему имя используя наш уникальный ID
reply->setObjectName(Уникальный ID); который был помещен в наш локальный Hash
MANAGER делает запрос на сервер... и когда срабатывает сигнал QNetworkAccessManager::finished(QNetworkReply*) вызывается соответсвующий слот, который обрабатывает QNetworkReply* reply и вот тут то нам и пригодится наш QHash<Уникальный ID, Задание>, слот полуив на входе объект QNetworkReply* reply
получает его имя (которое по сути деля является уникальным ID) методом reply->objectName(),
далее по полученому имени (оно же является ID) ищет в хэше  QHash<Уникальный ID, Задание> объект задания , и уже в это задание помещает  тело ответа сервера...
Далее делает emit MASTERy в котором передает полученное задание (задание внутри содержит свой уникальный ID)— и мастер доволен... он знает какое задание какому аккаунту принадлежит, ибо тоже имеет свой QHash<Уникальный ID, Задание> и задание содержит в свой структуре тело ответа сервера. Далее Мастер уже готовит новое задание... снова генерирует уникальный ID, передает вокеру и так далее по кругу

Если все подсумировать, выходит нужно иметь 2 хэша QHash<Уникальный ID, Задание>
Один в MASTER другой в MANAGER
которые помогут MASTERу понять какой ответ сервера к какому аккаунту соответсвует...


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: rudireg от Октябрь 30, 2016, 11:29
Возник новый вопрос по работе с cookie.

Программа работает с несколькими аккаунтами инстаграм, каждый аккаунт имеет свои cookie
QNetworkCookieJar* cookie = new QNetworkCookieJar;

Программа для посылки сетевых запросов использует один объект QNetworkAccessManager - который работает в отдельном одном потоке.
Поток принимает сигналы на обработку сетевых запросов  и помещает их на исполнение в очередь объекта QNetworkAccessManager
Перед каждым сетевым запросом устанавливается нужный cookie очередного аккаунта
QNAM->setCookieJar(cookie);

ВОПРОС: если объект QNetworkAccessManager  принял в очередь на выполнение несколько сетевых запросов
             (при этом каждый раз указывался новый cookie в объект QNetworkAccessManager )
             Не будет ли мешанины работы с куками?
             Если в очереди на выполнение 10 запросов, то как QNetworkAccessManager  узнает с каким cookie  работать?



Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: rudireg от Октябрь 30, 2016, 13:27
Сделал опыт...
Поставил в очередь QNetworkAccessManager два сетевых запроса... на два разных сайта...
каждый раз при запросе QNetworkAccessManager  получает отдельный QNetworkCookieJar
QNAM->setCookieJar(new QNetworkCookieJar);

После выполнения обоих запросов, смотрю что содержат мои 2 объекта QNetworkCookieJar
И вижу следующее, один пуст, а второй имеет объединенные куки с обоих сайтов.

Как вариант использовать не один QNetworkAccessManager 
а каждый раз при каждом новом запросе создавать новый QNetworkAccessManager 


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: Bepec от Октябрь 30, 2016, 14:42
куки жар можно ставить в QNetworkRequest. А вы его скорее всего ставите в QNAM. Не надо так!!!


Название: Re: Как организовать многопоточность? Выбор модели
Отправлено: rudireg от Октябрь 30, 2016, 14:52
куки жар можно ставить в QNetworkRequest. А вы его скорее всего ставите в QNAM. Не надо так!!!
В таком случае мне придется забыть про
QNAM->setCookieJar(new QNetworkCookieJar);

И в ручную помещать куки в QNetworkRequest.
А потом, при получении ответа... в ручную парсить куки для их сохранения.