Replies: 4 comments 1 reply
-
The The constructor that takes an initializer list has to do extra work to determine what kind of json it's creating. It's there for readability, not performance. You are also not optimizing, which significantly reduces the cost. Run your tests again at With You should also look at reserving the space in the array when you know that you're going to be writing a lot of elements:
|
Beta Was this translation helpful? Give feedback.
-
Hello @gregmarr !
You are right. Is it possible to construct the element directly in the vector in this case?
I see. Can't I use another type of constructor? In the best below I've used literals, but it's slower.
Below you can see another test, optimizing really changed the final number, but we have the same relative results.
This was the fastest. But what happens when I don't know the size before calling the method, does it worth it to do some extra pre-allocation and free the rest at the end? Details
#include "json.hpp"
#include <functional>
#include <iostream>
auto constexpr kIterations{1000000};
auto test1() {
auto subArray = nlohmann::json::array();
for (auto i = 0; i < kIterations; ++i) {
auto item = nlohmann::json::object();
item["description"] = "value";
item["lang"] = "value";
subArray.push_back(std::move(item));
}
return subArray;
}
auto test2() {
auto subArray = nlohmann::json::array();
for (auto i = 0; i < kIterations; ++i) {
auto item = nlohmann::json::object();
item["description"] = "value";
item["lang"] = "value";
subArray.emplace_back(std::move(item));
}
return subArray;
}
auto test3() {
auto subArray = nlohmann::json::array();
for (auto i = 0; i < kIterations; ++i) {
subArray.emplace_back(
nlohmann::json({{"description", "value"}, {"lang", "value"}}));
}
return subArray;
}
auto test4() {
auto subArray = nlohmann::json::array();
for (auto i = 0; i < kIterations; ++i) {
subArray.emplace_back(
nlohmann::json::object({{"description", "value"}, {"lang", "value"}}));
}
return subArray;
}
auto test5() {
auto subArray = nlohmann::json::array();
for (auto i = 0; i < kIterations; ++i) {
subArray.emplace_back(
nlohmann::json::parse(R"({"description": "value","lang": "value"})"));
}
return subArray;
}
auto test6() {
auto subArray = nlohmann::json::array();
for (auto i = 0; i < kIterations; ++i) {
subArray.emplace_back(R"({"description": "value","lang": "value"})"_json);
}
return subArray;
}
auto test7() {
auto subArray = nlohmann::json::array();
subArray.get_ptr<nlohmann::json::array_t *>()->reserve(kIterations);
for (auto i = 0; i < kIterations; ++i) {
auto item = nlohmann::json::object();
item["description"] = "value";
item["lang"] = "value";
subArray.emplace_back(std::move(item));
}
return subArray;
}
void measureTime(std::function<nlohmann::json(void)> func) {
auto start = std::chrono::high_resolution_clock::now();
auto ret = func();
auto end = std::chrono::high_resolution_clock::now();
std::cout << "Time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(end -
start)
.count()
<< "ms" << std::endl;
// Using the returned data to avoid unwanted optimizations
std::cout << "Size: " << ret.size() << std::endl;
}
int main() {
std::cout << "** Perfomance test ** " << std::endl;
std::cout << "Intermediate variable and push_back" << std::endl;
measureTime(test1);
std::cout << "Intermediate variable and emplace_back" << std::endl;
measureTime(test2);
std::cout << "No intermediate variable and emplace_back in place with "
"initializer list"
<< std::endl;
measureTime(test3);
std::cout << "No intermediate variable and emplace_back in place with "
"initializer list and object constructor"
<< std::endl;
measureTime(test4);
std::cout << "No intermediate variable and emplace_back in place with "
"parse and literal"
<< std::endl;
measureTime(test5);
std::cout << "No intermediate variable and emplace_back in place with "
"_json literal"
<< std::endl;
measureTime(test6);
std::cout << "Intermediate variable and emplace_back with pre-allocation"
<< std::endl;
measureTime(test7);
return 0;
}
|
Beta Was this translation helpful? Give feedback.
-
I don't think so, and I don't think it would matter. The cost is mostly in the constructing, not the inserting into the array. If you want to see the construction cost of the various methods, you can remove the
Definitely not. If you don't know at least the approximate size, just let the |
Beta Was this translation helpful? Give feedback.
-
I'll take a look at that then. Details
#include "json.hpp"
#include <functional>
#include <iostream>
auto constexpr kIterations{1000000};
void test1() {
for (auto i = 0; i < kIterations; ++i) {
auto item = nlohmann::json::object();
item["description"] = "value";
item["lang"] = "value";
}
}
void test2() {
for (auto i = 0; i < kIterations; ++i) {
auto item = nlohmann::json::object();
item.emplace("description", "value");
item.emplace("lang", "value");
}
}
void test3() {
for (auto i = 0; i < kIterations; ++i) {
auto object = nlohmann::json({{"description", "value"}, {"lang", "value"}});
}
}
void test5() {
for (auto i = 0; i < kIterations; ++i) {
auto object =
nlohmann::json::parse(R"({"description": "value","lang": "value"})");
}
}
void test6() {
for (auto i = 0; i < kIterations; ++i) {
auto object = R"({"description": "value","lang": "value"})"_json;
}
}
void measureTime(std::function<void(void)> func) {
auto start = std::chrono::high_resolution_clock::now();
func();
auto end = std::chrono::high_resolution_clock::now();
std::cout << "Time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(end -
start)
.count()
<< "ms" << std::endl;
}
int main() {
std::cout << "** Perfomance test ** " << std::endl;
std::cout << "test1" << std::endl;
measureTime(test1);
std::cout << "test2" << std::endl;
measureTime(test2);
std::cout << "test3" << std::endl;
measureTime(test3);
std::cout << "test5" << std::endl;
measureTime(test5);
std::cout << "test6" << std::endl;
measureTime(test6);
return 0;
}
Ok. Thank you for the detailed information! |
Beta Was this translation helpful? Give feedback.
-
Hi!
I'm making some tests and trying to get the fastest way to insert JSON objects into an array.
The thing is that in my tests, it's faster to create an intermediate variable every time like this
Than avoiding the intermediate variable and inserting directly the elements in the array
Why is this? Is there something wrong in the second proposal?
Here you have the code I used for testing.
Details
Output
Thank you.
Beta Was this translation helpful? Give feedback.
All reactions