[PR #201] [MERGED] fix: resolve 100% CPU usage in stdio buffer by replacing O(n²) Byte concatenation with BytesIO #217

Closed
opened 2026-02-15 21:16:16 -05:00 by yindo · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/langgenius/dify-plugin-sdks/pull/201
Author: @biubiuqiu
Created: 9/4/2025
Status: Merged
Merged: 9/8/2025
Merged by: @Yeuoly

Base: mainHead: fix/performance-stdio-buffer


📝 Commits (2)

  • 9203ded fix: improve stream reading and buffering logic
  • 63c63b6 fix: Re-add accidentally deleted line

📊 Changes

1 file changed (+21 additions, -9 deletions)

View changed files

📝 python/dify_plugin/core/server/stdio/request_reader.py (+21 -9)

📄 Description

Description

Problem

The StdioRequestReader caused 100% CPU usage due to a critical O(n²) performance bottleneck in buffer management. The inefficient buffer += data operations were consuming massive CPU resources through repeated memory allocations and copies.

Issues identified:

  • buffer += data creates new bytes objects on every append, copying the entire existing buffer
  • CPU pegged at 100% during data processing due to quadratic memory operations
  • Flame graph analysis revealed buffer += data as the primary CPU hot spot
  • For large data streams, this becomes a severe performance bottleneck

Solution

Replaced inefficient bytes concatenation with BytesIO for optimal buffer management:

  • Before: buffer += data → O(n²) memory copies → 100% CPU usage
  • After: buffer.write(data) → O(n) linear writes → Normal CPU usage

Performance Impact

For processing 1MB of data in 64KB chunks:

  • Memory copies reduced: ~8.5MB → ~1MB (85% reduction)
  • Time complexity: O(n²) → O(n)
  • CPU usage: From 100% sustained → Normal levels
  • Memory allocation overhead: Dramatically reduced

Root Cause

Python's bytes concatenation with += operator is inherently expensive for growing buffers. Each operation:

  1. Allocates new memory for combined size
  2. Copies existing buffer content
  3. Copies new data
  4. Deallocates old buffer

This results in exponential CPU consumption as buffer size grows.

Changes Made

  • Import BytesIO from io module
  • Replace buffer = b"" with buffer = BytesIO()
  • Use buffer.write(data) instead of buffer += data
  • Maintain identical line-processing logic for backward compatibility

Testing

  • Code compiles without syntax errors
  • Maintains existing functionality and API compatibility
  • CPU usage returns to normal levels
  • No changes to external interfaces or behavior

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/langgenius/dify-plugin-sdks/pull/201 **Author:** [@biubiuqiu](https://github.com/biubiuqiu) **Created:** 9/4/2025 **Status:** ✅ Merged **Merged:** 9/8/2025 **Merged by:** [@Yeuoly](https://github.com/Yeuoly) **Base:** `main` ← **Head:** `fix/performance-stdio-buffer` --- ### 📝 Commits (2) - [`9203ded`](https://github.com/langgenius/dify-plugin-sdks/commit/9203ded7d5b9e48e3f43ee361d73ec846092597e) fix: improve stream reading and buffering logic - [`63c63b6`](https://github.com/langgenius/dify-plugin-sdks/commit/63c63b6beb30d0253e93a3052459b632e9aeab0c) fix: Re-add accidentally deleted line ### 📊 Changes **1 file changed** (+21 additions, -9 deletions) <details> <summary>View changed files</summary> 📝 `python/dify_plugin/core/server/stdio/request_reader.py` (+21 -9) </details> ### 📄 Description # Description ## Problem The StdioRequestReader caused 100% CPU usage due to a critical O(n²) performance bottleneck in buffer management. The inefficient buffer += data operations were consuming massive CPU resources through repeated memory allocations and copies. ## Issues identified: - buffer += data creates new bytes objects on every append, copying the entire existing buffer - CPU pegged at 100% during data processing due to quadratic memory operations - Flame graph analysis revealed buffer += data as the primary CPU hot spot - For large data streams, this becomes a severe performance bottleneck # Solution Replaced inefficient bytes concatenation with BytesIO for optimal buffer management: - Before: buffer += data → O(n²) memory copies → 100% CPU usage - After: buffer.write(data) → O(n) linear writes → Normal CPU usage ## Performance Impact For processing 1MB of data in 64KB chunks: - Memory copies reduced: ~8.5MB → ~1MB (85% reduction) - Time complexity: O(n²) → O(n) - CPU usage: From 100% sustained → Normal levels - Memory allocation overhead: Dramatically reduced ## Root Cause Python's bytes concatenation with += operator is inherently expensive for growing buffers. Each operation: 1. Allocates new memory for combined size 2. Copies existing buffer content 3. Copies new data 4. Deallocates old buffer This results in exponential CPU consumption as buffer size grows. ## Changes Made - Import BytesIO from io module - Replace buffer = b"" with buffer = BytesIO() - Use buffer.write(data) instead of buffer += data - Maintain identical line-processing logic for backward compatibility ## Testing - Code compiles without syntax errors - Maintains existing functionality and API compatibility - CPU usage returns to normal levels - No changes to external interfaces or behavior --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
yindo added the pull-request label 2026-02-15 21:16:16 -05:00
yindo closed this issue 2026-02-15 21:16:16 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify-plugin-sdks#217