Я использую vc2011, и получается, что std :: async (std :: launch :: async, ...) немного глючит (иногда он не порождает новые потоки и запускает их параллельно, но вместо этого повторно использует потоки и запускают задачу один за другим). Это слишком медленно, когда я выполняю дорогостоящие сетевые вызовы. Поэтому я решил, что напишу свою собственную асинхронную функцию. Я застрял, хотя, где должно быть std :: обещать вживую? В 1) функция потока, 2) асинхронная функция или 3) функция вызывающего абонента.Замена std :: async с собственной версией, но где должно быть std :: prom live?
Код:
#include <future>
#include <thread>
#include <iostream>
#include <string>
#include <vector>
std::string thFun() {
throw std::exception("bang!");
return "val";
}
std::future<std::string> myasync(std::promise<std::string>& prms) {
//std::future<std::string> myasync() {
//std::promise<std::string> prms; //needs to outlive thread. How?
std::future<std::string> fut = prms.get_future();
std::thread th([&](){
//std::promise<std::string> prms; //need to return a future before...
try {
std::string val = thFun();
prms.set_value(val);
} catch(...) {
prms.set_exception(std::current_exception());
}
});
th.detach();
return fut;
}
int main() {
std::promise<std::string> prms; //I really want the promise hidden iway in the myasync func and not live here in caller code but the promise needs to outlive myasync and live as long as the thread. How do I do this?
auto fut = myasync(prms);
//auto fut = myasync(); //Exception: future already retrieved
try {
auto res = fut.get();
std::cout << "Result: " << res << std::endl;
} catch(const std::exception& exc) {
std::cout << "Exception: " << exc.what() << std::endl;
}
}
Я не могу показаться, чтобы пройти мимо того факта, что станд :: обещание нужно пережить функции асинхронной (и жить до тех пор, как нить), так что обещание Я не могу жить как локальная переменная в функции async. Но std :: prom тоже не должен жить в коде вызывающего абонента, так как вызывающему нужно знать только о фьючерсах. И я не знаю, как сделать обещание жить в функции потока, поскольку async нужно вернуть будущее, прежде чем он даже вызовет функцию fun. Я почесываю голову над этим.
У кого-нибудь есть идеи?
Редактировать: Я подчеркиваю это здесь, поскольку верхний комментарий немного дезинформирован. Хотя по умолчанию для std :: asycn разрешен режим отмены, когда явно задана политика запуска std :: launch :: async, она должна вести себя так, как будто «потоки порождаются и запускаются сразу» (см. Формулировку в en .cppreference.com/ж/CPP/резьба/асинхронный). См. Пример в pastebin.com/5dWCjjNY для одного случая, когда это не поведенческое поведение, наблюдаемое в vs20011. Решение отлично работает и ускорило мое приложение в реальном мире в 10 раз.
Редактировать 2: MS исправил ошибку. Более подробную информацию здесь: https://connect.microsoft.com/VisualStudio/feedback/details/735731/std-async-std-launch-async-does-not-behave-as-std-thread
«Иногда он не порождает новые потоки и запускает их параллельно, но вместо этого повторно использует потоки и запускает задачу один за другим». Это не глючит; вот как это разрешено работать. В спецификации нет гарантии, что какой-либо конкретный асинхронный вызов будет работать в другом потоке от предыдущих или будущих асинхронных вызовов.Если вы этого хотите, просто создайте кучу потоков, вставьте их в контейнер и присоедините их, когда захотите вернуть данные. –
В будущем, пожалуйста, разместите свой код непосредственно в своем вопросе, а не ссылайтесь на внешний сайт. – ildjarn
@Nicol. Ты уверен? Как я понимаю при использовании std :: launch :: async, он должен действовать так, как если бы поток был порожден. Согласно http://en.cppreference.com/w/cpp/thread/async «Если политика и std :: launch :: async! = 0 (бит асинхронизации установлен), генерирует новый поток выполнения, как если бы std :: thread (f, args ...), за исключением того, что если функция f возвращает значение или генерирует исключение, она сохраняется в состоянии общего доступа, доступном через std :: future, который async возвращает вызывающему ». – petke