Closed WhackoJacko closed 9 years ago
You can get a small improvement by adding DJANGO_REACT['DEBUG'] = False
to your settings, this sets NODE_ENV=production
.
I've generally wrapped the rendering in a DEBUG
check...
if django_react.settings.DEBUG:
markup = component.render_container()
else:
markup = component.render_to_string()
Performance is fast for dev, and on prod - where the rendering typically matters most - you can usually cache the generated markup.
In any case, the rendering cost is high and definitely needs to be improved. I suspect - but haven't profiled - that a lot of the cost is booting up node and loading everything in.
I took a poke around the React gem for Rails and it looks like they spin up a number of JS processes so that they have a pool to utilise on demand (https://github.com/reactjs/react-rails#server-rendering-1). My major road block on pursuing this is a strong desire to avoid the complexity which comes from managing that pool. If there is a lib, or third party solution (supervisor..?) perhaps that would be of use.
I'll leave this open as it's a large problem.
The priority is some sort of profiling suite which can indicate the bottlenecks.
Thanks again, Mark. Will keep my eye on this issue.
Yeah, the overhead on a cold boot of the renderer was the big bottleneck. I got a ~50 fold increase in performance when I switched over to a prototype of a render server which sits alongside the python process and responds over HTTP.
The rendering performance problem is down to the issue that every call to render_component requires a cold boot of node before anything gets rendered. Switching to a persistent, standalone node process would alleviate that overhead.
The only issues I can see with a persistent process sitting alongside the python process are:
standalone render server performance as a percentage of django_react.render_component
--------------------------------------------------------------------------------
max: 8.61138243181%
min: 1.86210436925%
avg: 2.3553003031%
median: 2.05074496877%
django_react.render_component
--------------------------------------------------------------------------------
times: [0.21702003479003906, 0.21471405029296875, 0.2179570198059082, 0.21650290489196777, 0.21557211875915527, 0.21570301055908203, 0.21838903427124023, 0.21029996871948242, 0.21512484550476074, 0.21892595291137695, 0.21367788314819336, 0.21283388137817383, 0.21916508674621582, 0.21521496772766113, 0.21786785125732422, 0.21573996543884277, 0.2140181064605713, 0.22343897819519043, 0.2166588306427002, 0.21626591682434082, 0.2243211269378662, 0.214310884475708, 0.2212519645690918, 0.22001218795776367, 0.21599102020263672]
max: 0.224321126938
min: 0.210299968719
mean: 0.216839103699
median: 0.216265916824
render via standalone node instance
--------------------------------------------------------------------------------
times: [0.019317150115966797, 0.004524946212768555, 0.0044269561767578125, 0.005631208419799805, 0.004354953765869141, 0.004359006881713867, 0.004597902297973633, 0.004567861557006836, 0.005520820617675781, 0.00423884391784668, 0.004435062408447266, 0.004353046417236328, 0.004564046859741211, 0.004564046859741211, 0.0044438838958740234, 0.00471806526184082, 0.004436969757080078, 0.004353046417236328, 0.004261970520019531, 0.0042459964752197266, 0.004274129867553711, 0.004177093505859375, 0.004342079162597656, 0.004431009292602539, 0.004540205001831055]
max: 0.019317150116
min: 0.00417709350586
mean: 0.00510721206665
median: 0.00443506240845
I'll update this when I've pushed a functional replacement for the current render process.
@WhackoJacko
The latest codebase and PyPI version spins up a dedicated render server which offers some massive performance boosts.
When rendering a simple 'Hello, World' component, my machine is now averaging 3% of the time formerly required.
By default, there is an initial overhead when the first component is rendered, which is down to the render server being spun up, but every successive render call will be massively faster.
If you want to avoid the first render's overhead and start with a warm render server, define DJANGO_REACT['START_RENDER_SERVER_ON_INIT'] = True
, this will cause the render server to boot during your python server's startup.
Here's some perf starts comparing the new render against the older one.
(django-react)~/Projects/django-react $ python django_react/tests/performance/run_tests.py
Running perf test with a warm render server...
DJANGO_REACT['RENDERER'] = 'django_react.render_server.ReactRenderServer' perf test
--------------------------------------------------------------------------------
Total time taken to render a component 25 times: 0.154497146606
Times: [0.06791496276855469, 0.00417780876159668, 0.003203868865966797, 0.0030939579010009766, 0.003473043441772461, 0.004724025726318359, 0.003371000289916992, 0.003133058547973633, 0.005461931228637695, 0.0033960342407226562, 0.0039010047912597656, 0.0035049915313720703, 0.004064083099365234, 0.0034401416778564453, 0.003448963165283203, 0.003170013427734375, 0.003443002700805664, 0.003534078598022461, 0.0033609867095947266, 0.003365039825439453, 0.003216981887817383, 0.0036149024963378906, 0.003699064254760742, 0.00333404541015625, 0.003450155258178711]
Max: 0.0679149627686
Min: 0.003093957901
Mean: 0.00617988586426
Median: 0.00344896316528
Running perf test with a render server booted on demand...
DJANGO_REACT['RENDERER'] = 'django_react.render_server.ReactRenderServer' perf test
--------------------------------------------------------------------------------
Total time taken to render a component 25 times: 0.473686933517
Times: [0.388322114944458, 0.004202127456665039, 0.0031290054321289062, 0.0032699108123779297, 0.0031850337982177734, 0.0045430660247802734, 0.0034651756286621094, 0.0034558773040771484, 0.005578041076660156, 0.003610849380493164, 0.003265857696533203, 0.0032219886779785156, 0.0037429332733154297, 0.0033538341522216797, 0.0035910606384277344, 0.003610849380493164, 0.0033957958221435547, 0.0032958984375, 0.0032989978790283203, 0.003326892852783203, 0.0033888816833496094, 0.0035238265991210938, 0.0032958984375, 0.003248929977416992, 0.003364086151123047]
Max: 0.388322114944
Min: 0.00312900543213
Mean: 0.0189474773407
Median: 0.00338888168335
Running perf test with a renderer which boots node on every render request...
DJANGO_REACT['RENDERER'] = 'django_react.renderer.ReactRenderer' perf test
--------------------------------------------------------------------------------
Total time taken to render a component 25 times: 5.52515673637
Times: [0.2518901824951172, 0.21484017372131348, 0.2172248363494873, 0.21650409698486328, 0.22143292427062988, 0.22011089324951172, 0.21518206596374512, 0.22161293029785156, 0.21700501441955566, 0.21958208084106445, 0.22993087768554688, 0.22188711166381836, 0.22236108779907227, 0.21548700332641602, 0.22033190727233887, 0.2214500904083252, 0.22034907341003418, 0.22076106071472168, 0.21924901008605957, 0.21874308586120605, 0.2151811122894287, 0.21937799453735352, 0.22022104263305664, 0.23113703727722168, 0.2133040428161621]
Max: 0.251890182495
Min: 0.213304042816
Mean: 0.221006269455
Median: 0.22011089325
Having simple component:
_rendercomponent takes about 1 second. Is there any way to improve speed of rendering? Setting _djangowebpack.settings.DEBUG to True doesn`t seem to help.