Ruby: Release the GVL during native parsing - #2263
Open
joelhawksley wants to merge 1 commit into
Open
Conversation
Run the native parser without the Ruby GVL so independent parses can execute concurrently. Temporarily lock mutable source strings while native parsing reads their buffers, and ensure cleanup on exceptions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 63a5a5bc-fa32-4a66-8dcd-944e49c575c6
joelhawksley
marked this pull request as ready for review
August 17, 2026 20:22
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Release Ruby's GVL while
herb_parseprocesses a template so independent parses can run concurrently in Ruby threads.This came out of profiling Action View template precompilation with ReActionView. Native parsing was a significant hotspot, but threaded precompilation could not parallelize it while the extension held the GVL.
Implementation
herb_parsethroughrb_thread_call_without_gvlniland frozen inputsrb_ensureto unlock the source and free the parser arena if parsing or Ruby object conversion raisesOnly the native parse runs without the GVL. Converting the C AST into Ruby objects still runs with the GVL, so this improves threaded throughput without claiming linear scaling.
Benchmark
I measured precompilation of 100 synthetic 100-line Action View templates using ReActionView/Herb with four threads on Ruby 3.4.10 (arm64 macOS). Herb location tracking and HTML parsing were disabled to match the rendering-only fast path under investigation.
In an alternating five-run comparison, patched Herb had an 89 ms median versus 120 ms for stock Herb. A separate, steadier stock series had a 104 ms median, putting the observed wall-clock improvement at roughly 14-26%. These short runs are noisy, so the range is more representative than a single percentage.
Validation
clang-format --dry-run --Werror ext/herb/extension.cnilinput through the existing parser suite