Reduce peak memory on import by 62x - #1186
Conversation
There was a problem hiding this comment.
Pull request overview
This PR refactors the PyThaiNLP library to reduce memory usage and import time by converting eagerly-loaded module-level variables (tokenizers and tries) into lazily-loaded, LRU-cached functions. This prevents expensive data structures from being loaded immediately when the module is imported.
Changes:
- Converted global tokenizer and trie constants to lru_cache decorated functions that load on-demand
- Extracted Thai2Fit tokenizer initialization into a separate module with lazy loading
- Updated all references throughout the codebase to call the new lazy-loading functions
- Modified function signatures to accept Optional parameters instead of using the old constants as defaults
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| pythainlp/tokenize/init.py | Converted DEFAULT_WORD_DICT_TRIE, DEFAULT_SYLLABLE_DICT_TRIE, and THAI2FIT_TOKENIZER to lazy-loaded functions |
| pythainlp/tokenize/thai2fit.py | New module containing lazy-loaded Thai2Fit tokenizer function |
| pythainlp/tokenize/core.py | Updated to use lazy-loaded trie functions; changed custom_dict parameter default to None |
| pythainlp/tokenize/newmm.py | Updated to call word_dict_trie() function and handle Optional[Trie] parameter |
| pythainlp/tokenize/multi_cut.py | Updated to call word_dict_trie() function and handle Optional[Trie] parameter |
| pythainlp/tokenize/longest.py | Updated to call word_dict_trie() function and handle Optional[Trie] parameter |
| pythainlp/util/wordtonum.py | Converted module-level tokenizers to lazy-loaded functions |
| pythainlp/util/time.py | Converted module-level tokenizer to lazy-loaded function |
| pythainlp/util/spell_words.py | Converted module-level tokenizer to lazy-loaded function |
| pythainlp/util/phoneme.py | Converted module-level tokenizer to lazy-loaded function |
| pythainlp/word_vector/core.py | Updated to call thai2fit_tokenizer() function |
| pythainlp/ulmfit/core.py | Changed tok_func parameter default from callable to None with lazy initialization |
| pythainlp/ulmfit/tokenizer.py | Updated to call thai2fit_tokenizer() function |
| pythainlp/augment/word2vec/thai2fit.py | Updated to call thai2fit_tokenizer() function |
| tests/core/test_tokenize.py | Updated test to call word_dict_trie() function |
| tests/extra/testx_tokenize.py | Updated tests to call word_dict_trie() function |
Comments suppressed due to low confidence (1)
pythainlp/tokenize/core.py:883
- Debug print statement should be removed. This appears to be leftover debugging code that will print "HEHE" every time a Tokenizer is instantiated.
self.__trie_dict = Trie([])
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
f01e495 to
b78fc0a
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Thank you for this PR. The library use case was primarily tokenization back at the time, so it kinda made sense to load the dictionary immediately when import, to simplify things and because it will eventually be loaded anyway (as it is the main use case). Since the library is growing and offers more functionality. That assumption no longer holds. |
Co-authored-by: Arthit Suriyawongkul <arthit@gmail.com>
Co-authored-by: Arthit Suriyawongkul <arthit@gmail.com>
|
|
Merged. Thank you @what-in-the-nim |



What does this changes
Refactor by moving expensive loading variable into LRU cached function
What was wrong
Most of the variables, tokenizer and tries, are initialized in the module scope, so when we do
import pythainlp, this will unnecessarily load everything into the RAM. This also affect the import time too.How this fixes it
I move everything inside the function to prevent sudden execution (lazy) and wrap it with
functools.lru_cacheto cache the result for future access.This is the minimal script to test the behavior
Branch
devThis PR
Import time is ~18x faster and peak RAM is reduced by ~62x
Your checklist for this pull request