Я использую vc2011, и получается, что std:: async (std:: launch:: async,...) немного глючит (иногда он не порождает новые потоки и запускает их параллельно, но вместо этого повторно использует потоки и запускает задачу один за другим). Это слишком медленно, когда я выполняю дорогостоящие сетевые вызовы. Поэтому я решил, что напишу свою собственную асинхронную функцию. Я застрял, хотя, где должно быть std:: обещать вживую? В 1) функции потока, 2) асинхронная функция или 3) функция вызывающего абонента.
код:
#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;
}
}
Кажется, что я не могу понять, что std:: prom необходимо пережить асинхронную функцию (и жить до тех пор, пока поток), так что обещание не может жить как локальная переменная в функции 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