Here is a quick comparison of Rust vs Python on your data.
On my computer Rust takes 2.8 microseconds and Python takes 16.9 microseconds, so the Rust one is around 6 times faster. Keep in mind that there may be other considerations in choosing a language. In particular the Rust code here is many more lines of code, the two implementations behave differently in the case of malformed input, there may be a faster JSON library for Python than the one in the standard library, etc.
Rust
// # Cargo.toml
// [dependencies]
// serde = "1.0"
// serde_derive = "1.0"
// serde_json = "1.0"
#![feature(test)]
#![allow(dead_code)]
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
extern crate test;
use std::collections::BTreeMap as Map;
static J: &str = r#"{
"errors": [
{
"type": "node",
"nodeId": "abcd-efgh",
"nodeUri": "http://example.com",
"tags": {"site": "lon"},
"error": "Connection refused",
"internal": true
},
{
"type": "series",
"tags": {"site": "lon"},
"error": "Aggregation too heavy, too many rows from the database would have to be fetched to satisfy the request!",
"internal": true
}
],
"result": [
{
"hash": "deadbeef",
"tags": {"foo": "bar"},
"values": [[1300000000000, 42.0]]
},
{
"hash": "beefdead",
"tags": {"foo": "baz","tutu":"toto","ici":"maintenant"},
"values": [[1300000000000, 42.0]]
}
],
"range": {
"end": 1469816790000,
"start": 1469809590000
},
"statistics": {}
}"#;
#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
struct Lucilecoutouly {
errors: Vec<ApiError>,
result: Vec<ApiResult>,
range: Range,
statistics: Statistics,
}
#[derive(Deserialize)]
#[serde(deny_unknown_fields, rename_all = "camelCase")]
struct ApiError {
#[serde(rename = "type")]
error_type: ErrorType,
node_id: Option<String>,
node_uri: Option<String>,
#[serde(default)]
tags: Map<String, String>,
error: String,
internal: bool,
}
#[derive(Deserialize)]
#[serde(rename_all = "lowercase")]
enum ErrorType {
Node,
Series,
}
#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
struct ApiResult {
hash: String,
#[serde(default)]
tags: Map<String, String>,
values: Vec<(u64, f64)>,
}
#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
struct Range {
end: u64,
start: u64,
}
#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
struct Statistics {}
#[bench]
fn bench_json(b: &mut test::Bencher) {
b.iter(|| serde_json::from_str::<Lucilecoutouly>(J).unwrap());
}
Python
J = """{
"errors": [
{
"type": "node",
"nodeId": "abcd-efgh",
"nodeUri": "http://example.com",
"tags": {"site": "lon"},
"error": "Connection refused",
"internal": true
},
{
"type": "series",
"tags": {"site": "lon"},
"error": "Aggregation too heavy, too many rows from the database would have to be fetched to satisfy the request!",
"internal": true
}
],
"result": [
{
"hash": "deadbeef",
"tags": {"foo": "bar"},
"values": [[1300000000000, 42.0]]
},
{
"hash": "beefdead",
"tags": {"foo": "baz","tutu":"toto","ici":"maintenant"},
"values": [[1300000000000, 42.0]]
}
],
"range": {
"end": 1469816790000,
"start": 1469809590000
},
"statistics": {}
}"""
import json, timeit
def test():
json.loads(J)
if __name__ == '__main__':
N = 1000 * 1000
T = timeit.timeit("test()", number=N, setup="from __main__ import test")
print("%sns" % int(T / N * 1000 * 1000 * 1000))