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

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

Страниц: 1 2 [3]   Вниз
  Печать  
Автор Тема: Как организовать многопоточность? Выбор модели  (Прочитано 21625 раз)
rudireg
Гость
« Ответ #30 : Октябрь 27, 2016, 22:03 »

В одном потоке живет объект QNetworkAccessManagerа, через него отправляются 1000 запросов, дальше он начинает ждать ответы... Вот пришел первый ответ - отдали его на обработку воркеру, пришел второй ответ - еще одному воркеру, и т.д.
Нет нужды отправлять запросы и пулить ответы в нескольких потоках, ждать легко может только один поток - дело не хитрое. Улыбающийся

В общем:
1) Workerформирует URL по которому следует перейти и передает его (URL) менеджеру.
2) Менеджер имея в себе объект QNetworkAccessManager получив URL делает запрос в интернет.
   Далее срабатывает сигнал void QNetworkAccessManager::finished(QNetworkReply *reply)
   который запускает СЛОТ.  Слот который будет вызван где расположить??? В менеджере или в Вокере??
   Думаю что в менеджере наверное.
Видимо не совсем понимаю как отдать ответ вокеру...
    
« Последнее редактирование: Октябрь 27, 2016, 22:05 от rudireg » Записан
rudireg
Гость
« Ответ #31 : Октябрь 28, 2016, 00:38 »

И каким образом  объект QNetworkAccessManager работающий в отдельном потоке принимает запросы (URL) от вокеров? Через очередь делать?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #32 : Октябрь 28, 2016, 07:07 »

И каким образом  объект QNetworkAccessManager работающий в отдельном потоке принимает запросы (URL) от вокеров? Через очередь делать?
Может не стоит ударяться в специфику (QNetworkAccessManager, URL и.т.п.). Суть та же и без нее. Основной способ взаимодействия  - просто посылка сигнала связанного как QueuedConnection или AutoConnection. Параметры этого сигнала автоматычно заносятся в EventLoop получателя, и когда он выйдет в событийный цикл (exec) он получит этот сигнал. Поэтому не надо городить своих очередей.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #33 : Октябрь 28, 2016, 07:42 »

Видимо не совсем понимаю как отдать ответ вокеру...
Многопоточность нужно добавлять тогда, когда она нужна. Улыбающийся
Для отправки последовательно раз в секунду тысячи запросов и ожидания ответов не нужны потоки. Qt умеет отправлять такие запросы и получать на них ответ асинхронно, не блокируя GUI. Все это легко можно сделать в одном GUI-потоке.
А вот если, например, нужна долгая обработка ответов - то потоки пригодятся. Вот вы описали задачу, один раз в секунду лайкать фотографию от имени одного из 1000 аккаунтов - это легко сделать без всяких потоков.
В общем, нужны детали. Не стоит тянуть многопоточность, только для того что-бы она была. В чем вы видите необходимость параллельной обработки, что будет по вашему долго обрабатываться?
Записан
rudireg
Гость
« Ответ #34 : Октябрь 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

  
« Последнее редактирование: Октябрь 28, 2016, 16:41 от rudireg » Записан
rudireg
Гость
« Ответ #35 : Октябрь 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у понять какой ответ сервера к какому аккаунту соответсвует...
« Последнее редактирование: Октябрь 28, 2016, 21:31 от rudireg » Записан
rudireg
Гость
« Ответ #36 : Октябрь 30, 2016, 11:29 »

Возник новый вопрос по работе с cookie.

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

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

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

« Последнее редактирование: Октябрь 30, 2016, 11:33 от rudireg » Записан
rudireg
Гость
« Ответ #37 : Октябрь 30, 2016, 13:27 »

Сделал опыт...
Поставил в очередь QNetworkAccessManager два сетевых запроса... на два разных сайта...
каждый раз при запросе QNetworkAccessManager  получает отдельный QNetworkCookieJar
QNAM->setCookieJar(new QNetworkCookieJar);

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

Как вариант использовать не один QNetworkAccessManager 
а каждый раз при каждом новом запросе создавать новый QNetworkAccessManager 
« Последнее редактирование: Октябрь 30, 2016, 13:36 от rudireg » Записан
Bepec
Гость
« Ответ #38 : Октябрь 30, 2016, 14:42 »

куки жар можно ставить в QNetworkRequest. А вы его скорее всего ставите в QNAM. Не надо так!!!
Записан
rudireg
Гость
« Ответ #39 : Октябрь 30, 2016, 14:52 »

куки жар можно ставить в QNetworkRequest. А вы его скорее всего ставите в QNAM. Не надо так!!!
В таком случае мне придется забыть про
QNAM->setCookieJar(new QNetworkCookieJar);

И в ручную помещать куки в QNetworkRequest.
А потом, при получении ответа... в ручную парсить куки для их сохранения.
Записан
Страниц: 1 2 [3]   Вверх
  Печать  
 
Перейти в:  


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