Skip to content

Memoize serializer classes #101

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

Merged
merged 1 commit into from
Dec 17, 2019

Conversation

amcaplan
Copy link

These should be memoizable, and it avoids (in most cases, though an explicit jsonapi_serializer_class_name can't benefit here since we can't know it'll be reliably the same) the need for an expensive #constantize operation.

Monkeypatching in this change in a production application I'm working with shaved ~5% off total request time when dealing with large numbers of included models. I also threw together a quick Rails app to give an accurate-ish benchmark (I believe #constantize performs worse when there are more constants/namespaces to choose from, but don't quote me on it): https://github.com/amcaplan/jsonapi-serializer-benchmark/blob/master/lib/tasks/benchmark.rake

Using benchmark-ips, on the master branch, I saw 5.92/sec with a high of 5.949/sec over 3 runs, as opposed to 6.31/sec with a low of 6.276/sec over 3 runs on my branch, meaning it's a 6.5% performance increase (in that particular case) and the variance of the two sets of figures didn't overlap (so it's pretty clearly a win).

These should be memoizable, and it avoids (in most cases) the need for
an expensive `#constantize` operation.
@djones
Copy link
Collaborator

djones commented Dec 17, 2019

Thanks for this PR @amcaplan. I did a quick benchmark to understand what impact this PR has more than 2 years on.

This is what I ran:

require 'benchmark'
require 'factory_girl'

require './lib/jsonapi-serializers'
require './spec/support/serializers'
require './spec/support/helpers'
require './spec/support/factory.rb'

include FactoryGirl::Syntax::Methods

user = create(:user)
long_comments = create_list(:long_comment, 1000, user: user)
post = create(:post, :with_author, long_comments: long_comments)

# Make sure each long-comment has a circular reference back to the post.
long_comments.each { |c| c.post = post }

Benchmark.bm do |benchmark|
  benchmark.report("serialize") {
    100000.times do
      JSONAPI::Serializer.serialize(post)
    end
  }

  benchmark.report("serialize with author and long-comments includes") {
    100.times do
      JSONAPI::Serializer.serialize(
        post,
        {include: ['author', 'long-comments']}
      )
    end
  }

  benchmark.report("serialize with recursive loading of relationships") {
    100.times do
      JSONAPI::Serializer.serialize(
        post,
        {include: ['long-comments.post.author', 'author', 'long-comments']}
      )
    end
  }
end

This PR definitely improves performance.

Screen Shot 2019-12-16 at 7 30 33 PM

(source)

It clearly has a positive impact of at least 5%. With a gain of closer to 9% when simply running serializer 100,000 times. These measurements aren't too far off yours... although I would guess I'm using a newer version of Ruby than you did at the time.

Copy link
Collaborator

@djones djones left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🍍 LGTM

@amcaplan
Copy link
Author

It's reassuring to know my work has withstood the test of time! 😂

In all seriousness, thanks for accelerating this. I'm delighted that the performance work I did 2 years ago can start making other people's apps faster.

@djones djones merged commit 5d08c9f into fotinakis:master Dec 17, 2019
@amcaplan amcaplan deleted the memoize-serializer-class branch April 20, 2021 23:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants