feature(extract-python:docling): avoid locking the GIL by using page batches and result buffering - #15
Merged
Conversation
…batches and result buffering
ClemDoum
force-pushed
the
chore(extract)/docling-per-page-parallelism
branch
from
September 10, 2026 12:27
3ea360e to
c32dd8b
Compare
ClemDoum
marked this pull request as ready for review
September 10, 2026 12:54
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.
Description
When running Docling parsing the GIL was locked trigger heartbeat timeouts when processing long documents.
Indeed, while some docling are async calls from the Python interpreter pov (torch or numpy calls), other are truely blocking like calling the pdf backend or other pure python CPU ops. Call
to_thread(converter.convert_all)is blocking in these case because we're processing potentially hundred of pages at the same time.This PR aims at avoid this GIL lock and optimize GPU inference by processing batches of constant size in terms of pages.
All documents are split into pages and
convert_allis called on a constant size batch of pages.More precisely, batching operates at 2 differente level:
page_batch_sizeis the number of pages concurrent sent to the GPU (or other processing unit) and processed in parallelmax_page_batchesis the number of consecutive batch which are sent to the Docling converter and processed sequentiallyThe second level of batching avoids calling the converter for a single batch of pages. The underlying reason is that calling
converter.convert_allas a fixed cost that we'd like to mutualize between batches (calling the PDF backend for instance).Additionnally some custom logic had to be implement in order to deal with the fact that
converter.convert_all(docs, page_range)takes a singlepage_rangearguments for all processed documents.The choice made here was to split processing of small and large docs (n_pages < (or >) max_pages = page_batch_size * max_page_batches):
max_pagespages, we hence try to group their pages in batches ofmax_pagespages using bin fillingmax_pagespages, we split them in chunks ofmax_pagesand process them by chunk. For their last chunk of pages which is usually less thanmax_pagespages, we buffer them by page range in order to process the remainder of different documents togetherBecause this batching strategy process documents unordered, a result buffer was implemented to aggregate partial results form pages. Since results can be large in size, we offload buffering to the filesystem when necessary.
Changes
extract-coreAdded
ResultBufferConfigBatchConcurrencySettingsto theDoclingSettingsto set docling page concurrency (and other options)Changed
extract-pythonAdded
DoclingPipeline