New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve JSON.parse() performance #345

Open
wants to merge 1 commit into
base: master
from

Conversation

Projects
None yet
1 participant
@Watson1978

Watson1978 commented Feb 25, 2018

When use non-frozen string as hash key with rb_hash_aset(), it will duplicate and freeze the string internally.
To avoid duplicate and freeze, this patch will give a frozen string in rb_hash_aset().

FYI)
If you use string as hash key, hash object always might have frozen string as key.

irb(main):001:0> hash = { "foo" => 42 }
=> {"foo"=>42}
irb(main):002:0> hash.keys[0].frozen?
=> true

This patches will be 15 % faster.

Environment

  • Machine : MacBook (Retina, 12-inch, 2017)
  • OS : macOS 10.13.3
  • Compiler : Apple LLVM version 9.1.0 (clang-902.0.31)
  • Ruby : ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin17]

Before

$ ruby bench.rb
Warming up --------------------------------------
                json    14.000  i/100ms
Calculating -------------------------------------
                json    144.882  (± 1.4%) i/s -    728.000  in   5.025682s

After

$ ruby bench.rb
Warming up --------------------------------------
                json    16.000  i/100ms
Calculating -------------------------------------
                json    165.608  (± 1.8%) i/s -    832.000  in   5.025367s

Test code

require 'json'
require 'objspace'
require 'securerandom'
require 'benchmark/ips'

obj = []

1000.times do |i|
  obj << {
    "id": i,
    "uuid": SecureRandom.uuid,
    "created_at": Time.now
  }
end

json = obj.to_json

Benchmark.ips do |x|
  x.report "json" do |iter|
    count = 0
    while count < iter
      JSON.parse(json)
      count += 1
    end
  end
end

@Watson1978 Watson1978 changed the title from Improve JSON_parse_string() performance to Improve JSON.parse() performance Feb 27, 2018

Use frozen string for hash key
When use non-frozen string for hash key with `rb_hash_aset()`, it will duplicate and freeze it internally.
To avoid duplicate and freeze, this patch will give a frozen string in `rb_hash_aset()`.

## Before
```
Warming up --------------------------------------
                json    14.000  i/100ms
Calculating -------------------------------------
                json    148.844  (± 1.3%) i/s -    756.000  in   5.079969s
```

### After
```
Warming up --------------------------------------
                json    16.000  i/100ms
Calculating -------------------------------------
                json    165.608  (± 1.8%) i/s -    832.000  in   5.025367s
```

### Test code
```
require 'json'
require 'securerandom'
require 'benchmark/ips'

obj = []

1000.times do |i|
  obj << {
    "id": i,
    "uuid": SecureRandom.uuid,
    "created_at": Time.now
  }
end

json = obj.to_json

Benchmark.ips do |x|
  x.report "json" do |iter|
    count = 0
    while count < iter
      JSON.parse(json)
      count += 1
    end
  end
end
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment