serde: ускорение десериализации пользовательских перечислений - PullRequest
1 голос
/ 23 апреля 2019

Моя программа разбирает достаточно большой JSON-документ (30 МБ), на машине с медленным процессором это занимает 70мс, я хочу ускорить процесс, и я узнаю, что 27% парсинга происходит в моем foo_document_type_deserialize, Возможно ли улучшить эту функцию, может быть, есть способ пропустить String распределение здесь: let s = String::deserialize(deserializer)?;?

Я полностью уверен, что строки, представляющие значения перечисления, не содержат специальных символов json, таких как \b \f \n \r \t \" \\, поэтому работа с неэкранированной строкой должна быть безопасной.

use serde::{Deserialize, Deserializer};

#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct FooDocument {
    // other fields...
    #[serde(rename = "type")]
    #[serde(deserialize_with = "foo_document_type_deserialize")]
    doc_type: FooDocumentType,
}

fn foo_document_type_deserialize<'de, D>(deserializer: D) -> Result<FooDocumentType, D::Error>
where
    D: Deserializer<'de>,
{
    use self::FooDocumentType::*;
    let s = String::deserialize(deserializer)?;
    match s.as_str() {
        "tir lim bom bom" => Ok(Var1),
        "hgga;hghau" => Ok(Var2),
        "hgueoqtyhit4t" => Ok(Var3),
        "Text" | "Type not detected" | "---" => Ok(Unknown),
        _ => Err(serde::de::Error::custom(format!(
            "Unsupported foo document type '{}'",
            s
        ))),
    }
}

#[derive(Debug, Clone, Copy)]
pub enum FooDocumentType {
    Unknown,
    Var1,
    Var2,
    Var3,
}

1 Ответ

4 голосов
/ 23 апреля 2019

Пользовательский импл, который вы написали, имеет форму, которую может генерировать serde_derive:

#[derive(Deserialize, Debug)]
pub enum FooDocumentType {
    #[serde(rename = "Text", alias = "Type not detected", alias = "---")]
    Unknown,
    #[serde(rename = "tir lim bom bom")]
    Var1,
    #[serde(rename = "hgga;hghau")]
    Var2,
    #[serde(rename = "hgueoqtyhit4t")]
    Var3,
}

Полученный производный код не выделяет память и в быстром микробенчмарке примерно в 2 раза быстрее по сравнению с вашим кодомкогда я измеряю следующее:

serde_json::from_str::<FooDocument>(r#"{"type":"hgga;hghau"}"#).unwrap()
...