мы можем сделать составную асин c функцию, используя packaged_task? - PullRequest
0 голосов
/ 13 апреля 2020

Я пытаюсь создать программу с использованием boost asio для создания HTTP-клиента:
сначала я использую basic_thread_pool для создания потоков, в которых в экземпляре общего указателя создается другой экземпляр подготовительного класса HttpSymbolPrepareGet, а затем запускается его метод GetDay:

boost::basic_thread_pool tp(MAXNUMBERTHREADS);
        for (auto symbol_each : symbols_vec)
        {           
            tp.submit([symbol_each, day, &resolve_addr]()
            {
                boost::shared_ptr<HttpSymbolPrepareGet> HttpSymbolPrepareGet_thread_func = boost::make_shared<HttpSymbolPrepareGet>(symbol_each, day, resolve_addr); 
                //4-8-2020 HttpSymbolPrepareGet HttpSymbolPrepareGet_thread_func(symbol_each, day, resolve_addr);
                HttpSymbolPrepareGet_thread_func->GetDay();
            }
            );


        }

затем в функции GetDay экземпляр HTTPClient создается в рамках общего указателя:

boost::shared_ptr<HTTPClient> client = boost::make_shared<HTTPClient>((HttpSymbolPrepareGet_shared_pointer_to_this_Get()));

, а также в функции GetDay запускается метод внутри HTTPClient с именем CreateTasks:

client->CreateTasks();

затем в методе CreateTasks создается карта http-запросов, и экземпляр HTTPRequest, заключенный в общий указатель, создается внутри для l oop, делая 24 запроса:

mClientRequestsVariables[m_HttpClient_request_name] = CreateRequest(hour, m_HttpClient_URL, mClientResolveAddr, mHttpClient_LoggingInstance_shared_pointer, HTTPClient_shared_pointer_to_this_Get())->shared_from_this() ;

, затем внутри класса HTTPRequest, там это следующие методы:
pupli c метод:

void Execute(boost::asio::yield_context, std::string,  boost::shared_ptr<std::map<std::string, boost::shared_ptr<HTTPResponse>>>);

и частные методы:

// Send the request message.
    void SendRequest(boost::asio::yield_context);

    // Read the status line.
    void ReadStatusLine(boost::asio::yield_context);

    // Now read the response headers.
    void ReadResponseHeaders(boost::asio::yield_context);

    // Now we want to read the response body.
    void ReadResponseBody(boost::asio::yield_context);

    void OnFinish(const boost::system::error_code&);
    //void on_finish_0(const boost::system::error_code&);

метод Execute выполняется как сопрограмма asio с использованием контекста yield и возврата void и внутри него, вызов async_connect, передавая его yield, сделан и Начиная с e c вызывается закрытый метод SendRequest.
эта структура основана на примере из книги asio, в которой она использует Execute как функцию, а затем SendRequest и другие закрытые методы в качестве обратных вызовов, которые записывают свои результаты в классе HTTPRespnose.

В моих первых испытаниях я изменил Execute и другие обратные вызовы с рекурсивной структуры на структуру сопрограмм, используя asio :: yield_context, и использовал spawn для запуска каждой задачи в io_service.

Затем я хочу сделать контейнер фьючерсов, затем подождать, пока какой-либо из фьючерсов будет использовать готовое будущее, чтобы вернуть экземпляр HTTPResponse-записи результата HTTPRequest для распаковки lzma и записи в файл csv.

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

И с этого момента я начал так смущаться.

Сначала я попытался сохранить модель сопрограммы, но просто поместил Execute в packaged_task, чтобы я мог добавить эту упакованную задачу в службу io с помощью post,
Это потребовало от меня изменить тип возвращаемого Execute с void на string в этом коде:

//4boost::packaged_task<std::string(boost::asio::yield_context,  std::string, std::map<std::string, boost::shared_ptr<HTTPResponse>>&)> task(boost::bind(&HTTPRequest::Execute, mClientRequestsVariables[m_HttpClient_request_name].get(), boost::placeholders::_1, m_HttpClient_request_name, Get_mHTTPClient_Responses_Map()));

Но это дало мне ошибки, связанные с привязкой, поэтому я сделал некоторый поиск, который предложил сделать общий указатель на задачу следующим образом:

//1typedef boost::packaged_task<std::string(boost::asio::yield_context, std::string, std::map<std::string, boost::shared_ptr<HTTPResponse>>)>  task_t;
//1boost::shared_ptr<task_t> task = boost::make_shared<task_t>(boost::bind(&HTTPRequest::Execute,  boost::placeholders::_1, m_HttpClient_request_name, Get_mHTTPClient_Responses_Map()));

, но он также дал ошибки поэтому я подумал, что это потому, что я должен поставить указатель после метода Execute в boost :: bind. Так что я изменил HTTPRequest для получения из enable_shared_from_this, и я добавил shared_from_this для boost :: bind в этом коде:

//20typedef boost::packaged_task<std::string(boost::shared_ptr<HTTPRequest>, boost::asio::yield_context, std::string, boost::shared_ptr<std::map<std::string, boost::shared_ptr<HTTPResponse>>>)>  task_t;
//20boost::shared_ptr<task_t> task = boost::make_shared<task_t>(boost::bind(&HTTPRequest::Execute, mClientRequestsVariables[m_HttpClient_request_name]->shared_from_this(), boost::placeholders::_2, m_HttpClient_request_name, Get_mHTTPClient_Responses_Map_shared_pointer()));  

, но потом, когда я добавляю io.post, используя эту задачу следующим образом:

//20boost::future<std::string> fut = (task->get_future());
//20mPendingData.push_back(std::move(fut)); // C++11 possible: (std::move(fut) when fut is a unique_future);    
//mIos.post(boost::bind(&task_t::operator(), task));

, но это также дало ошибку, связанную с привязкой.

но я читал, что сообщение нуждается в копируемом объекте "//// 4-7-2020 проблема в том, что параметр обработчика io_service :: post завершения должен быть CopyConstructible, как отмечено в требованиях обработчика Asio. Поэтому boost :: packaged_task не может быть опубликовано напрямую или перемещено. Существует обходной путь с помощью указателей, например, вы можете обернуть boost :: packaged_task с boost :: shared_ptr и связать его с operator (): "

, но затем я подумал перечитать документацию asio и я обнаружил, что это действительно новая ошибка для меня, говоря об универсальной модели asyn c и составленной функции asyn c.
честно говоря, я нашел ее настолько сложной для меня, особенно, что я не могу сопоставить черты типа Handler и async_result, но это показал мне, что есть что-то под названием use_future.

Итак, я прочитал, что я могу использовать что-то под названием use_future вместо yield_context. Я изменил Execute на:

std::string HTTPRequest::Execute(std::string request_name, boost::shared_ptr<std::map<std::string, boost::shared_ptr<HTTPResponse>>> mHTTPClient_Responses_Map_shared_pointer)

, и я изменил все обратные вызовы SendRequest ..., чтобы использовать use_future внутри все их async_read async_connect ...
Но при компиляции это дало мне новую ошибку:

Error   C2440   'return': cannot convert from 'void (__cdecl &)(boost::asio::yield_context)' to 'void (&)(boost::asio::yield_context)'  

изменено на:

Error   C2440   'return': cannot convert from 'void (__cdecl &)()' to 'void (&)()' 

Я действительно запутался и не знаю, что делать ??
я должен сделать Выполнить async_composed функцию ????
Packaged_task конвертирует обычную функцию в функцию async_composed ???

...