user3072517
user3072517

Reputation: 533

Vector of futures for breaking up tasks?

I have a response from a web service that if the number of data items is large, I want to split it up into smaller requests and perform the request and subsequent parsing of that request in parallel. Essentially, while the first request is parsing the data, the subsequent requests should be fetching it.

It seems that there are a number of approaches to doing this, and I am wondering if futures is appropriate in this case. I hear some comments that futures should not be used for IO, and arguments going the other way.

Effectively, I am trying to do this:

void Service::GetData(const Defn &defn) {
    // Split up the request into chunks if the  list is large
    size_t chunk_size = CONFIG.GetInt("Limits","BatchSize");
    if(chunk_size == 0) {
        auto response = GetResponse(defn);
        Parse(defn, *response);
    } else {
        std::vector<std::future<std::unique_ptr<Response>>> futures;
        for(int batch_num = 0; batch_num < (std::ceil(cardinality / chunk_size)); batch_num++) {
            futures.emplace_back(std::async(std::launch::async, &Service::GetResponse, defn, chunk_size, batch_num * chunk_size));
        }
        for(auto&& future : futures ) {
            Parse(defn, *future.get());
        }
    }
}

std::unique_ptr<Response> Service::GetResponse(const Defn &defn, size_t top, size_t skip) {
    // Do request and return response
}

However, I am getting an error "error C2064: term does not evaluate to a function taking 3 arguments" and I am not sure why. Do futures disallow putting them into containers such as a vector?

If so, should I be approaching this differently, or is there a different way to capture a list of futures? I.e. Do I have to use a packaged task?

Ideally, I suppose, this should be tied closer to the number of cores rather than just arbitrarily breaking up the response in chunks and then trying to create a thread for each chunk.

Upvotes: 0

Views: 367

Answers (1)

ikh
ikh

Reputation: 10417

futures.emplace_back(
    std::async(std::launch::async,
        &Service::GetResponse, pService, defn, chunk_size, batch_num * chunk_size)
//                             ^^^^^^^^
    );

Since GetResponse isn't static member function, you should give the object as parameter.


I don't know what you do exactly, so I can't give you specific advices >o<

However, if you interested in asynchronous task with future, I would introduce you boost.asio. It's an asynchronous I/O library (yes, ASynchronous I/O) which easily cooperate with std::future or boost::future. (See this my question)

In your code, I think Parse() also can go into future.

futures.emplace_back(
    std::async(std::launch::async,
        [&] { GetResponse(...); Parse(...); }
    )
);

If Parse don't need to run in the same thread or run sequently, I think it's better - you can run several Parse and several GetResponse in parallel.

Upvotes: 1

Related Questions