The Overlooked Tokenization Bottleneck: How CPUs Slow Down LLM Inference

After GPUs sped up, tokenization—once free—has become a new inference bottleneck under Python's GIL and in agent scenarios.
Tokenization has long been treated as a negligible rounding-error-level step in LLM inference. But once GPU performance is squeezed to the limit, the CPU-side tokenization in front of it starts leaving expensive accelerators spinning idle. The article traces three causes: faster downstream steps shift the relative bottleneck forward; in engines like SGLang and vLLM, tokenization is implemented in Rust/C++ yet must pass through the Python layer, constrained by the GIL into a single-threaded queue; and agent multi-turn tasks re-tokenize accumulated history each round, growing CPU workload while GPU load shrinks due to caching. Georgia Tech research shows that with ample CPU resources, time-to-first-token can drop by 1.47 to 7.11 times. Three fix paths diverge: Hugging Face rewrote its tokenization library for 3-30x single-thread speedups, Georgia Tech advocates more CPU cores, and PyTorch argues for moving tokenization entirely out of the Python process. Yet neither study can pin down tokenization's exact share of idle time, root-cause judgments differ, and no unified conclusion has emerged.
In the full pipeline of large model inference, tokenization has long been regarded as a step that requires no concern. Slicing sentences into the numerical sequences that models can read is a computation that seems utterly trivial compared to matrix multiplication, and for years it has indeed been treated as existing at the level of "rounding error." But as GPUs get faster and faster, this cheap step is becoming the new bottleneck for the entire machine.

Why Tokenization Went from "Free" to "Expensive"
When Hugging Face released its new-generation tokenization library, it offered a candid judgment: tokenization has historically never been a bottleneck. But they also listed the conditions under which that judgment breaks down—serving a large number of requests simultaneously, or repeatedly processing extremely long inputs.
The core of the change isn't tokenization itself, but the fact that everything downstream of it has gotten faster. The pipeline order of model inference is fixed: text must first be converted to tokens by the CPU before the GPU can start working. Once GPU-side performance has been squeezed to its limit, the "cheap" step in front of it is no longer free. The accelerator you paid a fortune for ends up waiting on a step that was never measured.
Tokenization is the first step in the large model inference pipeline: splitting raw text into the smallest units (tokens) in the model's vocabulary, then mapping them to integer ID sequences. Mainstream large models use subword tokenization algorithms such as BPE (Byte Pair Encoding), WordPiece, or Unigram, which statistically derive high-frequency substrings from training corpora as the vocabulary, balancing vocabulary size against coverage of out-of-vocabulary words. The quality of tokenization directly determines sequence length, context utilization efficiency, and the model's handling of multilingual content, code, and numbers. For this reason, a tokenizer is not a simple string-splitting tool but a component that must be released in tandem with model weights.
In terms of computational cost, tokenization is essentially table lookup plus a small amount of string matching, with complexity approximately linear in sequence length and unit cost far below self-attention or matrix multiplication in a Transformer. This is precisely why it has long been categorized as a "free" step—in an era when GPU compute was still scarce and the bottleneck was concentrated in model forward passes, the CPU side where tokenization lives had ample headroom to absorb this overhead. Only after model inference itself is substantially accelerated does this linear, single-threaded step sitting at the front of the critical path reveal its relative scarcity.
Python's Lock and the Real Cost in Production
According to an analysis by the LightSeek Foundation on the PyTorch blog, in the two mainstream inference engines SGLang and vLLM, tokenization is performed by high-speed libraries written in Rust or C++, but every call must pass through the Python layer. And Python's Global Interpreter Lock (GIL) stipulates that only one thread can execute Python code at any given moment, which places a single-file queue on the mandatory path of every request.
Nobody notices this problem at small-scale deployments. But when the service architecture is redesigned to make GPUs run faster—say, splitting prompt reading and response generation across different machines, or distributing the model's specialized components across an entire cluster—this bottleneck begins to cause real damage in production. In the original's words: every microsecond spent behind the lock is a microsecond the accelerator spends spinning idle waiting for input.
The Global Interpreter Lock (GIL) is a mechanism of the CPython interpreter: at any given moment, only one thread within the same process is allowed to execute Python bytecode. Its original purpose was to simplify memory management and thread-safe implementation of C extensions, but the cost is that multithreading cannot truly execute Python code in parallel, and can only yield execution during gaps when the lock is released. For I/O-bound tasks, threads can still switch while waiting, which works reasonably well; but for operations that must enter the Python layer on every call, the GIL constitutes a serialization checkpoint.
In inference engines like SGLang and vLLM, the tokenization library itself is implemented in Rust or C++ and is very fast, but scheduling and invocation still have to enter through Python bindings. This means that even if the underlying tokenization function is parallel, every call must re-contend for the GIL upon return. The per-call overhead is on the order of microseconds, seemingly negligible, but in service clusters handling hundreds to thousands of requests per second, these microseconds accumulate into visible queuing latency. It is worth noting that Python 3.13 has offered an experimental free-threaded build (removing the GIL), but mainstream inference frameworks have not yet fully migrated, and in the short term the GIL remains a structural constraint in real deployments.
Agent Scenarios Amplify the Problem
Research from Georgia Tech discovered the same "starvation" phenomenon from a different angle, and the problem is even more severe in the direction the industry is evolving.
Agents need to complete tasks progressively across multiple rounds of dialogue, with history accumulating continuously. Each round, the entire history must be re-tokenized on the CPU. Then again, the GPU's burden is actually shrinking—because most of the history has already been seen, and its results are cached. The workload of the cheap step is growing while the workload of the expensive step is contracting.
The most memorable data point from that research: given ample CPU resources (rather than a squeezed quota), the wait time from sending a request to receiving the first token was shortened by 1.47 to 7.11 times across the various configurations tested. In other words, that pause before the response begins is measurably a processor slicing text.
Three Fix Paths and Their Divergences
Faced with the same diagnosis, the solutions offered by various parties unfold in different directions:
Hugging Face rebuilt its tokenization library, achieving encoding paths 3 to 30 times faster than v0.23 on a single thread of an Apple M4 Max, with eight-worker scaling efficiency reaching 76% of linear—not an eightfold speedup, but not far off.
The Georgia Tech authors advocate configuring more CPU cores. The PyTorch analysis advocates moving this work out of the Python process entirely.
Interestingly, neither study could determine how much of the idle time is attributable to tokenization versus output reassembly, parsing, or launching tasks on the chip. The two also diverge on root cause: the PyTorch article sees Python's lock as the root cause, while the Georgia Tech research found that even when work is split into separate processes and the chip is fed pre-recorded instruction sequences, the GPU still remains underfed—so the GIL cannot be the whole story. Hugging Face's speed numbers come from a single Apple laptop chip, not a service cluster, and whether the gap can be closed where the real bottleneck appears has yet to be verified.
Linear scaling efficiency is a common metric for measuring the quality of multi-core parallelism: if N workers are used, the ideal speedup is N times, and the actual speedup divided by N is the scaling efficiency. Hugging Face reports 76% linear scaling with eight workers, meaning an actual speedup of about 6x rather than the theoretical 8x. The remaining loss typically comes from shared resource contention, uneven task distribution, or serialization overhead. This number matters because short, high-frequency tasks like tokenization are easily swallowed by scheduling overhead—the task itself is too short, and the coordination cost between workers can itself become the new bottleneck, so 76% efficiency is already respectable in engineering terms.
Meanwhile, the Time To First Token (TTFT) mentioned in the discussion is a key metric for interaction experience, referring to the time between when a user sends a request and when the first output token is received. It differs from total throughput: a system may have high overall throughput but a long TTFT, making it feel "laggy." In agent and streaming dialogue scenarios, TTFT directly determines the response speed users perceive, which is why the Georgia Tech study uses TTFT as its core measure—it precisely targets the spot where the tokenization bottleneck is most likely to be exposed: the wait after a request enters and before the GPU starts computing.
Two Answers from History
The gaming industry once encountered a similar problem: the CPU submits drawing commands to the graphics card, and once the graphics card gets faster, the act of submitting commands through the old programming interface itself becomes the reason the card spins idle. The card is ready, but the CPU is still talking. Vulkan and Metal were designed precisely as low-overhead interfaces to make this conversation cheaper. The chip didn't change; the way of expressing it did.
The storage industry took another path. Once flash memory became fast enough, the operating system's handling of each request—the block layer and completion interrupts—could no longer keep pace with the drive. The solution wasn't a leaner way of making requests, but a different arrangement: instead of waiting to be notified that work is complete, actively go check.
Graphics thinned out the middleman; storage moved the handoff off the critical path. Tokenization is being offered both solutions at once.
The analogy of Vulkan, Metal, and low-overhead graphics interfaces is worth expanding on. Under old interfaces like OpenGL, the CPU had to go through extensive validation, state management, and driver translation every time it submitted drawing commands, and the graphics card often spun idle between submissions. Vulkan and Metal moved this work earlier: allowing applications to pre-build command buffers, batch submissions, and directly manage memory and synchronization, significantly reducing per-frame CPU overhead. The essence isn't making the graphics card faster, but making the CPU "speak" more efficiently, thereby matching the already-accelerated GPU. This is highly isomorphic to the idea of moving tokenization out of the Python process and pre-constructing token sequences.
The storage-side replacement of interrupts with polling represents another philosophy. Under the traditional interrupt model, the device actively notifies the CPU after completing I/O, but every interrupt comes with context-switching and handling overhead; when NVMe SSDs get fast enough to respond at the microsecond level, interrupt overhead instead becomes dominant. Polling lets the CPU actively and frequently check the completion queue, sacrificing some idle-time energy efficiency in exchange for determinism and throughput at low latency. One path trims the middle layer, the other changes the handoff method, and together they illustrate: when one link suddenly gets fast, the accompanying coordination mechanism must be restructured in tandem, or the bottleneck will shift to a previously inconspicuous interface.
The Version That Could Have Been Built
A different design is not hard to imagine. The tokenizer could have lived outside the Python process from the very first day these inference engines were born, as an independent service with its own threads, passing tokens rather than text, never touching that lock. The cost would be that the people writing inference engines would have to maintain a more complex codebase and slower startup times, and researchers who like everything in a single Python file would lose the convenience of reaching in and modifying things at will.
The bill was deferred to those running the largest-scale clusters, paid in the form of accelerator idle time, coming due only when the accelerator is fast enough to notice.
That rounding error was never the tokenizer itself. It was the decision about where to put it.
One-line Summary
After GPUs sped up, tokenization—once considered free—has become a new inference bottleneck under Python's GIL and in agent scenarios.
Related articles

How Big Can Stars Really Get? The Physical Limits of the Largest Stars
Red supergiants are the largest stars by volume, with radii up to 2,000 times the Sun, engulfing the inner solar system. But there is no precise upper limit on stellar size—models predict up to 15,000 solar radii. The most massive blue stars are far smaller than red supergiants—biggest and heaviest are two different things.

Apple HomeView Smart Display Full Feature Breakdown: Wall-Mount or Desktop, $299
Apple launches HomeView, a $299 smart display with wall-mount and desktop options, 12MP camera for facial recognition, smart home control, music playback, and recipe step-by-step cooking. Full breakdown of watch faces, apps, privacy, and cooking integration.

Where Did the Promised New Studio Go? Craft Computing Answers After Five Years
Craft Computing's host responds to viewer questions: the new studio promised five years ago was shelved as construction costs soared from $30,000 to $75,000, and was replaced by a 168-square-foot garage conversion.