jjzjj

json - Crystal : slow json serialization of structs containing large strings

coder 2023-06-28 原文

我想知道为什么在 Crystal 中包含大字符串的结构的 json 序列化速度很慢。

下面的代码执行得相当差:

struct Page
  include AutoJson
  field :uri, String
  field :html, String
end

page = Page.new(url, html) # html is a string containing ±128KB of html

page.to_json

而以下 Javascript (Node.js) 或 Go 中的代码几乎是瞬时的(快 x10~x20 倍):

Node .js

page = { url: url, html: html }
JSON.stringify(page)

开始

type Page struct {
  Uri string `json="uri"`
  Html string `json="html"`
}

page = Page{ uri, html }

json, _ = json.Marshal(page)  

考虑到 Crystal 通常非常快(与 Go 相当并且比 V8 Javascript 快得多)这让我有点想知道这里发生了什么。

我已经对 Crystal 代码进行了一些试验,似乎这里的罪魁祸首是大字符串的双引号字符串转义(这在序列化 json 对象时显然是必需的)。但是为什么要花这么长时间,我不知道(多次分配,副本?)。

请注意,在这些示例中,html 是一个大约 128KB 的 html 文件,使用任何可用的同步方法从磁盘加载。在对这些片段进行基准测试时,显然没有考虑文件读取操作。

最佳答案

我在 macOS x86_64 上用 crystal 0.25.1 (LLVM 6.0.1)、go 1.10.3、node.js v8.11.2 测试了这个。

所有示例都将一个 161 KB 的 html 文件读入一个字符串,打开一个临时文件并进行 10.000 次序列化页面对象迭代并将其写入文件。

这会生成大约 1.5 GB 的 JSON,系统具有非常快的 PCIe SSD,因此 IO 吞吐量不是瓶颈。

我选择将数据实际写入文件,以确保编译器无法优化函数调用。

Crystal

require "json"
require "tempfile"
url = "http://www.example.org"
html = File.read("index.html")

record(Page, uri : String, html : String) do
  include JSON::Serializable
end

Tempfile.open("foo") do |io|
  10_000.times do
    page = Page.new(url, html)
    page.to_json(io)
  end
end

开始

package main

import (
  "encoding/json"
  "io/ioutil"
  "log"
  "os"
)

type Page struct {
  Uri  string `json="uri"`
  Html string `json="html"`
}

func main() {
  buf, err := ioutil.ReadFile("index.html")
  if err != nil {
    log.Fatal(err)
  }
  uri := "http://www.example.org"
  html := string(buf)
  file, err := ioutil.TempFile(os.TempDir(), "foo")
  if err != nil {
    log.Fatal(err)
  }
  defer os.Remove(file.Name())
  for i := 0; i < 10000; i++ {
    page := Page{uri, html}
    json, err := json.Marshal(page)
    if err != nil {
      log.Fatal(err)
    }
    _, err = file.Write(json)
    if err != nil {
      log.Fatal(err)
    }
  }
}

Node.js

const fs = require('fs')
const tmp = require('tmp')
const uri = 'http://www.example.org'
const html = fs.readFileSync('index.html')

tmp.file((err, path, fd) => {
  if (err) throw err;

  for(let i = 0; i < 10000; i++) {
    const page = { uri, html }
    const json = JSON.stringify(page)
    fs.writeSync(fd, json)
  }
})

结果

  • 进行:10.88 秒,8.5 MB RAM
  • crystal:12.62 秒,2 MB RAM,慢 1.16 倍
  • node.js:101.82 秒,75 MB RAM,慢 9.36 倍

请注意,我使用 --release 编译了 Crystal 示例并更新了 0.25.1 的代码。

Node.js 示例使用 v8 而不是 v10,因为 v10 与我用于临时文件的 node-tmp npm 模块不兼容。

基准测试是在配备 i7-5557U CPU、16 GB RAM 和 1 TB PCIe SSD 的 2015 年初 13"Retina MacBook Pro 上完成的。

关于json - Crystal : slow json serialization of structs containing large strings,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47952457/

有关json - Crystal : slow json serialization of structs containing large strings的更多相关文章

  1. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  2. ruby-on-rails - 如何使用 Rack 接收 JSON 对象 - 2

    我有一个非常简单的RubyRack服务器,例如:app=Proc.newdo|env|req=Rack::Request.new(env).paramspreq.inspect[200,{'Content-Type'=>'text/plain'},['Somebody']]endRack::Handler::Thin.run(app,:Port=>4001,:threaded=>true)每当我使用JSON对象向服务器发送POSTHTTP请求时:{"session":{"accountId":String,"callId":String,"from":Object,"headers":

  3. ruby - 用 YAML.load 解析 json 安全吗? - 2

    我正在使用ruby2.1.0我有一个json文件。例如:test.json{"item":[{"apple":1},{"banana":2}]}用YAML.load加载这个文件安全吗?YAML.load(File.read('test.json'))我正在尝试加载一个json或yaml格式的文件。 最佳答案 YAML可以加载JSONYAML.load('{"something":"test","other":4}')=>{"something"=>"test","other"=>4}JSON将无法加载YAML。JSON.load("

  4. ruby-on-rails - Rails 渲染带有驼峰命名法的 json 对象 - 2

    我在一个简单的RailsAPI中有以下Controller代码:classApi::V1::AccountsControllerehead:not_foundendendend问题在于,生成的json具有以下格式:{id:2,name:'Simpleaccount',cash_flows:[{id:1,amount:34.3,description:'simpledescription'},{id:2,amount:1.12,description:'otherdescription'}]}我需要我生成的json是camelCase('cashFlows'而不是'cash_flows'

  5. ruby - 使用 JSON gem 将自定义对象转换为 JSON - 2

    我正在学习如何使用JSONgem解析和生成JSON。我可以轻松地创建数据哈希并将其生成为JSON;但是,在获取一个类的实例(例如Person实例)并将其所有实例变量放入哈希中以转换为JSON时,我脑袋放屁。这是我遇到问题的例子:require"json"classPersondefinitialize(name,age,address)@name=name@age=age@address=addressenddefto_jsonendendp=Person.new('JohnDoe',46,"123ElmStreet")p.to_json我想创建一个.to_json方法,这样我就可以获

  6. ruby-on-rails - 如何使用驼峰键名称从 Rails 返回 JSON - 2

    我正在构建一个带有Rails后端的JS应用程序,为了不混淆snake和camelcases,我想通过从服务器返回camelcase键名来规范化这一切。因此,当从API返回时,user.last_name将返回user.lastName。我如何实现这一点?谢谢!编辑:添加Controller代码classApi::V1::UsersController 最佳答案 我的方法是使用ActiveModelSerializer和json_api适配器:在你的Gemfile中,添加:gem'active_model_serializers'创建

  7. ruby-on-rails - 如何将数组输出为 JSON? - 2

    我有以下内容:@array.inspect["x1","x2","adad"]我希望能够将其格式化为:client.send_message(s,m,{:id=>"x1",:id=>"x2",:id=>"adad"})client.send_message(s,m,???????)如何在????????中获得@array输出?空间作为ID?谢谢 最佳答案 {:id=>"x1",:id=>"x2",:id=>"adad"}不是有效的散列,因为您有键冲突它应该是这样的:{"ids":["x1","x2","x3"]}更新:@a=["x1

  8. ruby - 使用 jbuilder 创建具有动态哈希键的 JSON - 2

    这里我想输出带有动态组名的json而不是单词组@tickets.eachdo|group,v|json.group{json.array!vdo|ticket|json.partial!'tickets/ticket',ticket:ticketend}end@ticket是这样的散列{a:[....],b:[.....]}我想要这样的输出{a:[.....],b:[....]} 最佳答案 感谢@AntarrByrd,这个问题有类似的答案:JBuilderdynamickeysformodelattributes使用上面的逻辑我已经

  9. ruby - 展平嵌套的 json 对象 - 2

    我正在寻找一种将“json”散列展平为展平散列但将路径信息保留在展平键中的方法。例如:h={"a"=>"foo","b"=>[{"c"=>"bar","d"=>["baz"]}]}flatten(h)应该返回:{"a"=>"foo","b_0_c"=>"bar","b_0_d_0"=>"baz"} 最佳答案 这应该可以解决您的问题:h={'a'=>'foo','b'=>[{'c'=>'bar','d'=>['baz']}]}moduleEnumerabledefflatten_with_path(parent_prefix=nil)

  10. ruby-on-rails - 如何计算 Ruby/Rails 中 JSON 对象的数量 - 2

    Ruby中如何“一般地”计算以下格式(有根、无根)的JSON对象的数量?一般来说,我的意思是元素可能不同(例如“标题”被称为其他东西)。没有根:{[{"title":"Post1","body":"Hello!"},{"title":"Post2","body":"Goodbye!"}]}根包裹:{"posts":[{"title":"Post1","body":"Hello!"},{"title":"Post2","body":"Goodbye!"}]} 最佳答案 首先,withoutroot代码不是有效的json格式。它将没有包

随机推荐