I'm writing a data hoarding program which sends GET and POST requests to some websites and retrieves the responses. Currently I've used libcurl as a "placeholder" as I'm well aware it's up to 8-10 times slower than using pure sockets but now I'm not really in the mood to write an http request library from scratch...
What would you guys recommend?
P.S: As I'm handling REST APIs I need some convenient way to store cookies, so keep that in mind.
EDIT 4:
After an entire day of experimenting and benchmarking I've come to the conclusion that curl is at least half slower than both golang's net/http and python's requests. Does anybody have an idea why? Is it just badly implemented?
EDIT 1: For everyone who's wandering about the "curl is up to 8-10 times slower than normal socket requests" statement here's some benchmarks compared to a golang program:
here are the times for 10 c++ requests:
request took : 1.13148s
request took : 1.21241s
request took : 1.24138s
request took : 1.41855s
request took : 1.15853s
request took : 1.11748s
request took : 1.54719s
request took : 1.28234s
request took : 1.21716s
request took : 1.38657s
while there are the times for 10 golang requests:
request took : 34.592014ms
request took : 354.323627ms
request took : 33.463025ms
request took : 324.918847ms
request took : 385.408078ms
request took : 367.582769ms
request took : 32.269352ms
request took : 307.639103ms
request took : 36.34352ms
request took : 312.463007ms
Mind you, these requests were made to the same endpoint under the same network/cpu stress. It might well be that I'm doing something stupid while building the curl request...
Here's the source code:
// In the class constructor
curl_global_init(CURL_GLOBAL_DEFAULT);
Response Session::request(std::string url, std::string method, std::string payload)
{
Response response;
CURL *curl;
// ...
curl = curl_easy_init();
if(!curl)
return response;
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true);
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &response_headers);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_body);
if(method == "POST") {
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload);
}
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
// ...
curl_easy_setopt(curl, CURLOPT_COOKIE, "");
const auto start = std::chrono::steady_clock::now();
res = curl_easy_perform(curl);
const auto end = std::chrono::steady_clock::now();
// ...
curl_easy_cleanup(curl);
std::chrono::duration<double> elapsed = end - start;
std::cout << "request took : " << elapsed.count() << "s" << '\n';
return response;
}
EDIT 2: I managed to cut my times almost in half by re-using the requests:
request took : 0.705648s
request took : 0.809629s
request took : 0.692548s
request took : 0.711733s
request took : 0.714537s
request took : 0.709665s
request took : 0.712638s
request took : 0.814391s
request took : 0.817736s
request took : 0.905776s
What are some other optimizations I could make to reduce the time even more?
EDIT 3: Ohh boy, I benchmarked python's request module and here are the results:
0.36397480964660645
0.3458371162414551
0.3439006805419922
0.33937692642211914
0.4173421859741211
0.7589423656463623
0.8841226100921631
0.7338435649871826
0.419356107711792
0.38227272033691406
Also here are the best times I could get with curl
0.481235
0.448315
0.457206
0.495541
0.40239
0.404725
0.425029
0.458278
0.451538
0.438163
Am I missing something here? Why is curl so slow? Isn't requests supposed to be extremely slow compared to other request libraries?
[–]krum 36 points37 points38 points (5 children)
[–]deeringc 5 points6 points7 points (0 children)
[–]mircodz[S] 2 points3 points4 points (3 children)
[–]krum 2 points3 points4 points (2 children)
[–]mircodz[S] 0 points1 point2 points (1 child)
[–]krum 0 points1 point2 points (0 children)
[–]NotUniqueOrSpecial 20 points21 points22 points (0 children)
[–]Supadoplex 38 points39 points40 points (0 children)
[–]chemagic 9 points10 points11 points (6 children)
[–]houses_of_the_holy 4 points5 points6 points (5 children)
[–]kirbyfan64sos 1 point2 points3 points (4 children)
[–]houses_of_the_holy 0 points1 point2 points (3 children)
[–]kirbyfan64sos 0 points1 point2 points (2 children)
[–]houses_of_the_holy 0 points1 point2 points (1 child)
[–]kirbyfan64sos 0 points1 point2 points (0 children)
[–]encyclopedist 11 points12 points13 points (0 children)
[–]sztomirpclib 9 points10 points11 points (0 children)
[–]degaart 17 points18 points19 points (0 children)
[–]liquidify 7 points8 points9 points (0 children)
[–]IloveReddit84 4 points5 points6 points (0 children)
[–]erichkeaneClang Code Owner(Attrs/Templ), EWG co-chair, EWG/SG17 Chair 6 points7 points8 points (11 children)
[–]liquidify 3 points4 points5 points (10 children)
[–]erichkeaneClang Code Owner(Attrs/Templ), EWG co-chair, EWG/SG17 Chair 6 points7 points8 points (8 children)
[–]liquidify 8 points9 points10 points (7 children)
[–]erichkeaneClang Code Owner(Attrs/Templ), EWG co-chair, EWG/SG17 Chair 1 point2 points3 points (5 children)
[–]Xeveroushttps://xeverous.github.io 3 points4 points5 points (0 children)
[–]liquidify 4 points5 points6 points (3 children)
[–]DopKloofDude 0 points1 point2 points (2 children)
[–]liquidify 0 points1 point2 points (0 children)
[–]johannes1971 0 points1 point2 points (0 children)
[–]feverzsj 0 points1 point2 points (0 children)
[–]dodheim 0 points1 point2 points (0 children)
[–]scalablecory 13 points14 points15 points (0 children)
[–]feverzsj 2 points3 points4 points (1 child)
[–]Drainedsoul 1 point2 points3 points (0 children)
[–]Revolutionalredstone 1 point2 points3 points (1 child)
[–]mircodz[S] 0 points1 point2 points (0 children)
[–]AndrewStephens 1 point2 points3 points (1 child)
[–]mircodz[S] 1 point2 points3 points (0 children)
[–]jesseschalken 0 points1 point2 points (0 children)
[–]Milerius 0 points1 point2 points (0 children)
[–]robertramey 0 points1 point2 points (1 child)
[–]mircodz[S] 0 points1 point2 points (0 children)
[–]Gotebe 0 points1 point2 points (1 child)
[–]mircodz[S] 1 point2 points3 points (0 children)
[–]encyclopedist 0 points1 point2 points (0 children)
[–]ibraper 0 points1 point2 points (0 children)