【问题标题】:How to parse JSON larger than memory?如何解析大于内存的JSON?
【发布时间】:2023-01-15 14:37:06
【问题描述】:

我正在从事一个涉及大型 JSON 文件的项目,基本上是一个以 JSON 形式转储的多维数组,但整体大小会大于我拥有的内存量。如果我将它作为字符串加载,然后解析该字符串,那将消耗所有内存。

有什么方法可以限制内存消耗,比如只在特定索引之间检索数据?我可以仅使用 Nlohmann json 库/标准库来实现吗?

【问题讨论】:

  • 提示:流式解析器或NDJSON
  • 什么的多维数组?如果答案是数字,那么 JSON 可能不是正确的选择,原因与我们不使用 JSON 作为图像格式的原因相同。
  • @user4581301 结构数组——每个结构都有一个 std::tuple 的整数、整数本身和一个 std::vector<float>

标签: c++ json memory nlohmann-json


【解决方案1】:

RapidJSON 和其他人可以做到。这是一个使用 RapidJSON 的“SAX”(流式)API 的示例程序:https://github.com/Tencent/rapidjson/blob/master/example/simplereader/simplereader.cpp

这样,您将为解析过程中遇到的每个元素获得一个事件(回调)。解析本身的内存消耗会非常小。

【讨论】:

    【解决方案2】:

    您能否具体说明问题的背景

    • 您使用的是哪种编程语言(NodeJS、Vanilla JavaScript、Java、React)
    • 您的代码在什么环境下运行(服务器上的单体应用程序、AWS Lambda、无服务器)

    计算大型 JSON 文件会消耗服务器上的大量内存资源,也许会使您的应用程序崩溃。 我亲身体验过,使用 NodeJS 脚本计算大型 JSON 文件有效负载时,使用 8 GB 内存 RAM 在本地计算机上处​​理大型 JSON 文件不是问题。但是,尝试在服务器上运行的应用程序中运行那些大型 JSON 有效负载也会给我带来问题。

    我希望这有帮助。

    【讨论】:

    • 他已经在问题中使用c++ 标签指定了编程语言(C++)。
    【解决方案3】:

    使用 DAW JSON Link,https://github.com/beached/daw_json_link,您可以创建一个迭代器对/范围并一次迭代 JSON 数组 1 条记录。该库还有用于处理 JSONL 的例程,这在大型数据集中很常见。

    为了打开文件,我会使用类似 mmap/virtual alloc 的东西来为我们处理。库中的示例通过抽象文件映射的 daw::filesystem::memory_mapped_file_t 类型使用它。

    这样,内存映射文件允许操作系统根据需要将数据分页进/出,并且类似迭代器的接口将内存要求一次保持为一个数组元素的内存要求。

    下面演示了这一点,使用一个简单的记录

    struct Point {
      int x;
      int y;
    };
    

    执行此操作的程序看起来像

    #include <cassert>
    #include <daw/daw_memory_mapped_file.h>
    #include <daw/json/daw_json_iterator.h>
    #include <daw/json/daw_json_link.h>
    #include <iostream>
    
    struct Point {
      double x;
      double y;
    };
    
    namespace daw::json {
        template<>
        struct json_data_contract<Point> {
            using type =
              json_member_list<json_number<"x">, json_number<"y">>;
        };
    }
    
    int main( int argc, char** argv ) {
      assert( argc >= 1 );
      auto json_doc = daw::filesystem::memory_mapped_file_t<char>( argv[1] );
      assert( json_doc.size( ) > 2 );
      auto json_range = daw::json::json_array_range<Point>( json_doc );
      auto sum_x = 0.0;
      auto sum_y = 0.0;
      auto count = 0ULL;
      for( Point p: json_range ) {
        sum_x += p.x;
        sum_y += p.y;
        ++count;
      }
      sum_x /= static_cast<double>( count );
      sum_y /= static_cast<double>( count );
      std::cout << "Centre Point (" << sum_x << ", " << sum_y << ")
    ";
    }
    

    https://jsonlink.godbolt.org/z/xoxEd1z6G

    【讨论】:

      猜你喜欢
      • 2017-10-01
      • 1970-01-01
      • 2018-05-19
      • 1970-01-01
      • 2021-09-25
      • 2013-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多