并行 json 反序列化失败,并显示有效的 json

Parallel json deserialization fails with valid json

提问人:ZJaume 提问时间:7/18/2023 更新时间:7/19/2023 访问量:69

问:

我想使用 并行反序列化 json 值。当尝试在内部反序列化时,示例中的有效 json 失败,尽管在没有并行化的情况下被正确解析。代码如下:rayonserde-jsonpar_iter

use rayon::prelude::*; // 1.7.0
use serde_json::{Result, Value};

fn main() -> Result<()> {
    let data = r#"
        {
            "name": "John Doe",
            "age": 43,
            "phones": [
                "+44 1234567",
                "+44 2345678"
            ]
        }"#;
    let v: Value = serde_json::from_str(data)?;
    println!("Please call {} at the number {}", v["name"], v["phones"][0]);

    let mut batch = Vec::<String>::new();
    batch.push(data.to_string());
    batch.push(data.to_string());
    
    let _values = batch.par_iter()
        .for_each(|json: &String| {
            serde_json::from_str(json.as_str()).unwrap()
        });
        
    Ok(())
}

这就是错误

thread 'thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: Error("invalid type: map, expected unit", line: 2, column: 8)', src/main.rs:23:49

链接到 Playground。

IIRC,我见过其他使用内部的例子。这不推荐吗?就我而言,我想这样做,因为如果输入无效,我需要程序崩溃。par_iterunwrap

rust serde-json 人造丝

评论

4赞 kmdreko 7/19/2023
该方法不产生任何结果,因此闭包预计不会返回任何内容(又名)。因此,由于类型推断,正在尝试将 JSON 反序列化为单元类型,这是行不通的。.for_each_values()serde_json::from_str
1赞 rodrigo 7/19/2023
@kmdreko:确实,将内部代码更改为 Just Work。let v: Value = serde_json::from_str(json.as_str()).unwrap();
0赞 Chayim Friedman 7/19/2023
关于恐慌:除了错误之外,不鼓励在生产代码中恐慌。不过,为了方便起见,例子经常使用它(有人说这是不幸的)。在小脚本中,这也很好。并且此规则也不例外(try_for_each()存在)。par_iter()

答:

1赞 Finomnis 7/19/2023 #1

serde_json::from_str根据写入的变量类型自动确定其输出类型。但是,在您的例子中,不需要返回值,因此请尝试将其反序列化为 .for_eachfrom_str()

与注释一起使用以使其工作:map().collect(): Vec<Value>

use rayon::prelude::*; // 1.7.0
use serde_json::{Result, Value};

fn main() -> Result<()> {
    let data = r#"
        {
            "name": "John Doe",
            "age": 43,
            "phones": [
                "+44 1234567",
                "+44 2345678"
            ]
        }"#;
    let v: Value = serde_json::from_str(data)?;
    println!("Please call {} at the number {}", v["name"], v["phones"][0]);

    let mut batch = Vec::<String>::new();
    batch.push(data.to_string());
    batch.push(data.to_string());

    let values: Vec<Value> = batch
        .par_iter()
        .map(|json: &String| serde_json::from_str(json.as_str()).unwrap())
        .collect();

    println!("Values:\n{:#?}", values);

    Ok(())
}
Please call "John Doe" at the number "+44 1234567"
Values:
[
    Object {
        "age": Number(43),
        "name": String("John Doe"),
        "phones": Array [
            String("+44 1234567"),
            String("+44 2345678"),
        ],
    },
    Object {
        "age": Number(43),
        "name": String("John Doe"),
        "phones": Array [
            String("+44 1234567"),
            String("+44 2345678"),
        ],
    },
]

虽然老实说,使用起来有点奇怪;通常人们直接反序列化为结构:serde::Value

use rayon::prelude::*;
use serde::{Deserialize, Serialize};
use serde_json::Result;

#[derive(Debug, Serialize, Deserialize)]
struct Entry {
    name: String,
    age: u32,
    phones: Vec<String>,
}

fn main() -> Result<()> {
    let data = r#"
        {
            "name": "John Doe",
            "age": 43,
            "phones": [
                "+44 1234567",
                "+44 2345678"
            ]
        }"#;
    let v: Entry = serde_json::from_str(data)?;
    println!("Please call {} at the number {}", v.name, v.phones[0]);

    let mut batch = Vec::<String>::new();
    batch.push(data.to_string());
    batch.push(data.to_string());

    let values: Vec<Entry> = batch
        .par_iter()
        .map(|json: &String| serde_json::from_str(json.as_str()).unwrap())
        .collect();

    println!("Values:\n{:#?}", values);

    Ok(())
}
Please call John Doe at the number +44 1234567
Values:
[
    Entry {
        name: "John Doe",
        age: 43,
        phones: [
            "+44 1234567",
            "+44 2345678",
        ],
    },
    Entry {
        name: "John Doe",
        age: 43,
        phones: [
            "+44 1234567",
            "+44 2345678",
        ],
    },
]