{"@attributes":{"version":"2.0"},"channel":{"title":"DEV Community: Pierre DEL PERUGIA","description":"The latest articles on DEV Community by Pierre DEL PERUGIA (@delperugia).","link":"https:\/\/dev.to\/delperugia","image":{"url":"https:\/\/media2.dev.to\/dynamic\/image\/width=90,height=90,fit=cover,gravity=auto,format=auto\/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3279784%2Fa41a8584-3ee4-40d9-b4a4-8d83fee37c59.jpeg","title":"DEV Community: Pierre DEL PERUGIA","link":"https:\/\/dev.to\/delperugia"},"language":"en","item":{"title":"Introducing curlev: a highly-efficient asynchronous HTTP client","pubDate":"Mon, 23 Jun 2025 11:53:44 +0000","link":"https:\/\/dev.to\/delperugia\/introducing-curlev-a-highly-efficient-asynchronous-http-client-46jp","guid":"https:\/\/dev.to\/delperugia\/introducing-curlev-a-highly-efficient-asynchronous-http-client-46jp","description":"<p>I recently faced a significant challenge: making a large number of asynchronous HTTP calls to various servers, without waiting for responses but storing the data as it arrived. These requests originated from different parts of the program and were posted at various times.<\/p>\n\n<p>After evaluating several libraries (Async++ CURL, cpr, curl-multi-asio, curlcpp, restclient-cpp...), I found that none fully met my requirements. While <strong>cpr<\/strong> offered the best performance, its CPU usage was too high for me.<\/p>\n\n<p>So, I developed my own solution: <strong>curlev<\/strong>. It's built upon <strong>libcurl<\/strong>'s multi-interface and <strong>libuv<\/strong>'s asynchronous I\/O capabilities. <strong>curlev<\/strong> achieves performance very close to <strong>cpr<\/strong>, but with four times less CPU consumption (and half as much memory).<\/p>\n\n<div class=\"table-wrapper-paragraph\"><table>\n<thead>\n<tr>\n<th>Config<\/th>\n<th>Time<\/th>\n<th>CPU<\/th>\n<th>RSS<\/th>\n<th>s\u00b7CPU\u00b7MB<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>curlev<\/td>\n<td>2.162 s<\/td>\n<td>109%<\/td>\n<td>14'580 KB<\/td>\n<td><strong>34<\/strong><\/td>\n<\/tr>\n<tr>\n<td>cpr<\/td>\n<td>1.722 s<\/td>\n<td>501%<\/td>\n<td>22'016 KB<\/td>\n<td>185<\/td>\n<\/tr>\n<tr>\n<td>asyncpp-curl<\/td>\n<td>4.101 s<\/td>\n<td>126%<\/td>\n<td>335'744 KB<\/td>\n<td>1694<\/td>\n<\/tr>\n<tr>\n<td>curlcpp<\/td>\n<td>45.347 s<\/td>\n<td>99%<\/td>\n<td>625'204 KB<\/td>\n<td>27410<\/td>\n<\/tr>\n<tr>\n<td>curl-multi-asio<\/td>\n<td>100.102 s<\/td>\n<td>99%<\/td>\n<td>538'164 KB<\/td>\n<td>52083<\/td>\n<\/tr>\n<tr>\n<td>liblifthttp<\/td>\n<td>104.029 s<\/td>\n<td>99%<\/td>\n<td>528'128 KB<\/td>\n<td>53116<\/td>\n<\/tr>\n<\/tbody>\n<\/table><\/div>\n\n<p><strong>curlev<\/strong> offers three modes:<\/p>\n\n<p>A synchronous mode:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight cpp\"><code>  <span class=\"k\">auto<\/span> <span class=\"n\">http<\/span> <span class=\"o\">=<\/span> <span class=\"n\">HTTP<\/span><span class=\"o\">::<\/span><span class=\"n\">create<\/span><span class=\"p\">(<\/span> <span class=\"n\">global<\/span><span class=\"o\">::<\/span><span class=\"n\">async<\/span> <span class=\"p\">);<\/span>\n  <span class=\"k\">auto<\/span> <span class=\"n\">code<\/span> <span class=\"o\">=<\/span> <span class=\"n\">http<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">GET<\/span><span class=\"p\">(<\/span> <span class=\"s\">\"https:\/\/api.example.com\/get\"<\/span> <span class=\"p\">)<\/span>\n                  <span class=\"p\">.<\/span><span class=\"n\">exec<\/span><span class=\"p\">()<\/span>\n                  <span class=\"p\">.<\/span><span class=\"n\">get_code<\/span><span class=\"p\">();<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>An asynchronous mode (also available with std::future):<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight cpp\"><code>  <span class=\"k\">auto<\/span> <span class=\"n\">http<\/span> <span class=\"o\">=<\/span> <span class=\"n\">HTTP<\/span><span class=\"o\">::<\/span><span class=\"n\">create<\/span><span class=\"p\">(<\/span> <span class=\"n\">global<\/span><span class=\"o\">::<\/span><span class=\"n\">async<\/span> <span class=\"p\">);<\/span>\n  <span class=\"n\">http<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">GET<\/span><span class=\"p\">(<\/span> <span class=\"s\">\"https:\/\/api.example.com\/get\"<\/span> <span class=\"p\">)<\/span>\n      <span class=\"p\">.<\/span><span class=\"n\">start<\/span><span class=\"p\">();<\/span>\n  <span class=\"p\">...<\/span>\n  <span class=\"p\">...<\/span>\n  <span class=\"k\">auto<\/span> <span class=\"n\">code<\/span> <span class=\"o\">=<\/span> <span class=\"n\">http<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">join<\/span><span class=\"p\">().<\/span><span class=\"n\">get_code<\/span><span class=\"p\">();<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>A detached mode, with callback:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight cpp\"><code>  <span class=\"p\">{<\/span>\n    <span class=\"n\">HTTP<\/span><span class=\"o\">::<\/span><span class=\"n\">create<\/span><span class=\"p\">(<\/span> <span class=\"n\">global<\/span><span class=\"o\">::<\/span><span class=\"n\">async<\/span> <span class=\"p\">)<\/span>\n        <span class=\"o\">-&gt;<\/span><span class=\"n\">GET<\/span><span class=\"p\">(<\/span> <span class=\"s\">\"https:\/\/api.example.com\/get\"<\/span> <span class=\"p\">)<\/span>\n        <span class=\"p\">.<\/span><span class=\"n\">start<\/span><span class=\"p\">(<\/span> <span class=\"p\">[](<\/span> <span class=\"k\">const<\/span> <span class=\"k\">auto<\/span> <span class=\"o\">&amp;<\/span> <span class=\"n\">http<\/span> <span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                  <span class=\"k\">auto<\/span> <span class=\"n\">code<\/span> <span class=\"o\">=<\/span> <span class=\"n\">http<\/span><span class=\"p\">.<\/span><span class=\"n\">get_code<\/span><span class=\"p\">();<\/span>\n                <span class=\"p\">}<\/span> <span class=\"p\">);<\/span>\n  <span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>A <strong>std::shared_ptr<\/strong> is returned by the factory function <strong>HTTP::create<\/strong>, to ensure that the connection stays alive during the operation, even if the returned value goes out of scope.<\/p>\n\n<p>It also provides:<\/p>\n\n<ul>\n<li>all standard HTTP methods (GET, POST, PUT, PATCH, DELETE)<\/li>\n<li>query parameters, form data, MIME handling, and raw bodies<\/li>\n<li>custom headers and authentication<\/li>\n<li>received headers and body<\/li>\n<\/ul>\n\n<p>Here are 3 examples inspired from real usages:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight cpp\"><code><span class=\"k\">auto<\/span> <span class=\"n\">http<\/span> <span class=\"o\">=<\/span> <span class=\"n\">HTTP<\/span><span class=\"o\">::<\/span><span class=\"n\">create<\/span><span class=\"p\">(<\/span> <span class=\"n\">m_async<\/span> <span class=\"p\">);<\/span>\n<span class=\"n\">http<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">POST<\/span><span class=\"p\">(<\/span> <span class=\"n\">opr_callback_url<\/span> <span class=\"p\">)<\/span>\n    <span class=\"p\">.<\/span><span class=\"n\">add_headers<\/span><span class=\"p\">(<\/span> <span class=\"p\">{<\/span> <span class=\"p\">{<\/span> <span class=\"s\">\"X-Response-ID\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">response_id<\/span>  <span class=\"p\">}<\/span> <span class=\"p\">}<\/span> <span class=\"p\">)<\/span>\n    <span class=\"p\">.<\/span><span class=\"n\">start<\/span><span class=\"p\">(<\/span>\n        <span class=\"p\">[<\/span> <span class=\"n\">reference_id<\/span> <span class=\"p\">](<\/span> <span class=\"k\">const<\/span> <span class=\"k\">auto<\/span> <span class=\"o\">&amp;<\/span> <span class=\"n\">http<\/span> <span class=\"p\">)<\/span>\n        <span class=\"p\">{<\/span>\n          <span class=\"k\">if<\/span> <span class=\"p\">(<\/span> <span class=\"n\">http<\/span><span class=\"p\">.<\/span><span class=\"n\">get_code<\/span><span class=\"p\">()<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">200<\/span> <span class=\"p\">)<\/span>\n            <span class=\"n\">ack_notification<\/span><span class=\"p\">(<\/span> <span class=\"n\">reference_id<\/span> <span class=\"p\">);<\/span>\n          <span class=\"k\">else<\/span>\n            <span class=\"n\">log_warning<\/span><span class=\"p\">(<\/span>\n                <span class=\"s\">\"opr cb failed: \"<\/span> <span class=\"o\">+<\/span> <span class=\"n\">std<\/span><span class=\"o\">::<\/span><span class=\"n\">to_string<\/span><span class=\"p\">(<\/span> <span class=\"n\">http<\/span><span class=\"p\">.<\/span><span class=\"n\">get_code<\/span><span class=\"p\">()<\/span> <span class=\"p\">)<\/span> <span class=\"o\">+<\/span>\n                <span class=\"s\">\", ref=\"<\/span> <span class=\"o\">+<\/span> <span class=\"n\">reference_id<\/span> <span class=\"p\">);<\/span>\n        <span class=\"p\">}<\/span> <span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight cpp\"><code><span class=\"k\">auto<\/span> <span class=\"n\">http<\/span> <span class=\"o\">=<\/span> <span class=\"n\">HTTP<\/span><span class=\"o\">::<\/span><span class=\"n\">create<\/span><span class=\"p\">(<\/span> <span class=\"n\">m_async<\/span> <span class=\"p\">);<\/span>\n<span class=\"k\">auto<\/span> <span class=\"n\">code<\/span> <span class=\"o\">=<\/span>\n    <span class=\"n\">http<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">POST<\/span><span class=\"p\">(<\/span> <span class=\"n\">m_opr_server<\/span> <span class=\"o\">+<\/span> <span class=\"s\">\"\/user\/notify\"<\/span> <span class=\"o\">+<\/span> <span class=\"n\">user_id<\/span> <span class=\"p\">)<\/span>\n                <span class=\"p\">{<\/span> <span class=\"p\">{<\/span> <span class=\"s\">\"message_id\"<\/span><span class=\"p\">,<\/span> <span class=\"s\">\"account.created\"<\/span> <span class=\"p\">},<\/span>\n                  <span class=\"p\">{<\/span> <span class=\"s\">\"data\"<\/span>      <span class=\"p\">,<\/span> <span class=\"n\">data<\/span>              <span class=\"p\">}<\/span> <span class=\"p\">}<\/span> <span class=\"p\">)<\/span>\n        <span class=\"p\">.<\/span><span class=\"n\">exec<\/span><span class=\"p\">()<\/span>\n        <span class=\"p\">.<\/span><span class=\"n\">get_code<\/span><span class=\"p\">();<\/span>\n<span class=\"c1\">\/\/<\/span>\n<span class=\"k\">if<\/span> <span class=\"p\">(<\/span> <span class=\"n\">code<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">200<\/span> <span class=\"o\">&amp;&amp;<\/span> <span class=\"n\">http<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">get_content_type<\/span><span class=\"p\">()<\/span> <span class=\"o\">==<\/span> <span class=\"s\">\"application\/json\"<\/span> <span class=\"p\">)<\/span>\n  <span class=\"n\">json<\/span> <span class=\"o\">=<\/span> <span class=\"n\">http<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">get_body<\/span><span class=\"p\">();<\/span>\n<span class=\"k\">else<\/span>\n  <span class=\"k\">return<\/span> <span class=\"nb\">false<\/span><span class=\"p\">;<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight cpp\"><code><span class=\"k\">auto<\/span> <span class=\"n\">http<\/span> <span class=\"o\">=<\/span> <span class=\"n\">HTTP<\/span><span class=\"o\">::<\/span><span class=\"n\">create<\/span><span class=\"p\">(<\/span> <span class=\"n\">m_async<\/span> <span class=\"p\">);<\/span>\n<span class=\"k\">auto<\/span> <span class=\"n\">code<\/span> <span class=\"o\">=<\/span>\n    <span class=\"n\">http<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">GET<\/span><span class=\"p\">(<\/span> <span class=\"n\">m_opr_server<\/span> <span class=\"o\">+<\/span> <span class=\"s\">\"\/user\/\"<\/span> <span class=\"o\">+<\/span> <span class=\"n\">user_id<\/span> <span class=\"p\">)<\/span>\n        <span class=\"p\">.<\/span><span class=\"n\">authentication<\/span><span class=\"p\">(<\/span> <span class=\"s\">\"mode=bearer,secret=\"<\/span> <span class=\"o\">+<\/span> <span class=\"n\">token<\/span>  <span class=\"p\">)<\/span>\n        <span class=\"p\">.<\/span><span class=\"n\">exec<\/span><span class=\"p\">()<\/span>\n        <span class=\"p\">.<\/span><span class=\"n\">get_code<\/span><span class=\"p\">();<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>It doesn't provide (yet) JSON helper to check and parse the response.<\/p>\n\n<p>You can find the project on GitHub here <a href=\"https:\/\/github.com\/delperugia\/curlev\" rel=\"noopener noreferrer\">github<\/a>.<\/p>\n\n<p>Feel free to check it out and let me know your thoughts.<\/p>\n\n","category":["cpp","async","http","libcurl"]}}}