Skip to content

Commit 1456b12

Browse files
committed
Update cpulimiter library to version 1.5.0 with enhanced features and examples
- Refactor CpuLimiter to allow initialization with processes to limit. - Update README with detailed usage instructions and examples. - Modify MANIFEST.in to include necessary files. - Add new example scripts demonstrating basic usage and simple limits. - Improve setup.py with updated metadata and description.
1 parent 3e3c995 commit 1456b12

File tree

8 files changed

+234
-121
lines changed

8 files changed

+234
-121
lines changed

MANIFEST.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
include README.md
22
include LICENSE
3-
include pyproject.toml
3+
recursive-include examples *.py
44
recursive-include cpulimiter *.py

README.md

Lines changed: 56 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,73 @@
11
# cpulimiter 🚀
22

3-
A Python library for Windows to limit the CPU usage of running processes.
3+
[![PyPI version](https://img.shields.io/pypi/v/cpulimiter.svg)](https://pypi.org/project/cpulimiter/)
4+
[![PyPI pyversions](https://img.shields.io/pypi/pyversions/cpulimiter.svg)](https://pypi.org/project/cpulimiter/)
5+
[![PyPI license](https://img.shields.io/pypi/l/cpulimiter.svg)](https://github.com/Ahmed-Ashraf-dv/CPULimiter/blob/main/LICENSE)
46

5-
## Features ✨
7+
A simple, lightweight Python library for Windows to limit the CPU usage of any running process. Reduce CPU load, save power, and prevent overheating.
68

7-
- 🎯 Limit process CPU usage by a specified percentage.
8-
- 🔍 Target processes by Process ID (PID), executable name, or window title.
9-
- 🤝 Manage and control multiple limited processes simultaneously.
10-
- 🛠️ Utility functions to discover running and active processes.
9+
## 🤔 Why cpulimiter?
1110

12-
## Installation 📦
11+
Have you ever had a program like `Google Chrome`, a game, or a background task consume 100% of your CPU, making your system unresponsive and your fans spin like a jet engine?
12+
13+
`cpulimiter` solves this by throttling the application, allowing you to specify exactly how much CPU it can use. This is perfect for:
14+
15+
- 🎮 Capping the CPU usage of games to prevent overheating.
16+
- 🌐 Limiting resource-hungry browsers like Chrome or Edge when running multiple tabs.
17+
- 💼 Running heavy data processing or video encoding tasks in the background without slowing down your machine.
18+
- 🔋 Saving battery life on laptops by reducing the power consumption of demanding applications.
19+
- 🤫 Quieting down noisy CPU fans.
20+
21+
22+
## ✨ Features
23+
24+
- 🎯 **Limit CPU Usage:** Throttle process CPU usage to a specific percentage.
25+
- 🔍 **Flexible Targeting:** Target processes by Process ID (PID), executable name (`"chrome.exe"`), or even window title.
26+
- 🤝 **Multi-Process Management:** Control and limit multiple processes at the same time.
27+
- 🛠️ **Process Discovery:** Includes utility functions to find running applications and the active foreground window.
28+
- 🕊️ **Lightweight:** Has a minimal performance footprint and no external dependencies.
29+
30+
## 📦 Installation
1331

1432
```bash
1533
pip install cpulimiter
1634
```
1735

18-
## Quick Start 📖
36+
## 📖 Quick Start
1937

20-
The following example demonstrates how to limit `chrome.exe` to 5% of CPU usage (a 95% limit).
38+
The following example limits all `chrome.exe` processes to just 5% of a single CPU core's power (a 95% limit).
2139

2240
```python
2341
from cpulimiter import CpuLimiter
2442
import time
2543

26-
# 1. Initialize the limiter
27-
limiter = CpuLimiter()
28-
29-
# 2. Add the process directly by its name.
30-
# The library will find the PID for "chrome.exe" for you.
31-
limiter.add(process_name="chrome.exe", limit_percentage=95)
32-
33-
# 3. Start the limit
34-
# You can also start it by name.
35-
print("Limiting Chrome for 15 seconds...")
36-
limiter.start(process_name="chrome.exe")
44+
# 1. Find all "chrome.exe" processes and limit them to 5% CPU.
45+
# The limit is a percentage (0-100). 95 means "limit by 95%", so it can only use 5%.
46+
limiter = CpuLimiter({"chrome.exe": 95})
3747

48+
# 2. The limiter is now running in the background.
49+
# Let's keep it running for 15 seconds to see the effect.
50+
print("Limiting Chrome's CPU usage for 15 seconds...")
3851
time.sleep(15)
3952

40-
# 4. Stop the limit
41-
print("Stopping limit.")
42-
limiter.stop(process_name="chrome.exe")
43-
print("Process limit removed.")
53+
# 3. To stop limiting, simply call the shutdown() method.
54+
limiter.shutdown()
55+
print("CPU limit removed. Chrome is back to normal.")
4456
```
57+
*You can check your Task Manager to see the effect in real-time!*
58+
59+
## ⚙️ How It Works
4560

46-
## Examples 📚
61+
`cpulimiter` works by rapidly suspending and resuming the threads of a target process. For example, to achieve a 50% CPU limit, the library suspends the process for 10 milliseconds and then resumes it for 10 milliseconds, effectively cutting its CPU time in half. This cycle is managed by a lightweight, high-precision background thread.
4762

48-
Check out the `examples/` folder for different use cases:
63+
## 📚 Examples
4964

50-
- **`basic_usage.py`** - Simple introduction to the library
51-
- **`simple_limit.py`** - Manually limit specific applications
52-
- **`cpu_saver.py`** - Automatic CPU saver that limits all background apps
53-
- **`advanced_interactive.py`** - Interactive mode with real-time control
65+
Check out the `examples/` folder for more advanced use cases:
66+
67+
- **`basic_usage.py`** - A simple, manual introduction to the library's methods.
68+
- **`simple_limit.py`** - Manually limit a list of specific applications.
69+
- **`cpu_saver.py`** - An automatic CPU saver that throttles all applications that are not in the foreground.
70+
- **`advanced_interactive.py`** - An interactive command-line tool for real-time process management.
5471

5572
## API Reference
5673

@@ -91,4 +108,12 @@ Returns a dictionary containing the `pid`, `name`, and `title` of the foreground
91108

92109
#### `get_active_app_pids()`
93110

94-
Returns a dictionary of all processes with visible windows.
111+
Returns a dictionary of all processes with visible windows, mapping their PIDs to their executable names.
112+
113+
## 🤝 Contributing
114+
115+
Contributions, issues, and feature requests are welcome! Feel free to check the [issues page](https://github.com/Ahmed-Ashraf-dv/CPULimiter/issues).
116+
117+
## 📜 License
118+
119+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

cpulimiter/__init__.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
"""
2-
CPU Limiter
3-
A Python library to limit the CPU usage of processes.
2+
cpulimiter - A simple, lightweight Python library for Windows to limit CPU usage of processes.
43
"""
54

6-
__version__ = "1.0.0"
5+
__version__ = "1.5.0"
6+
__author__ = "Ahmed Ashraf"
77

88
from .limiter import CpuLimiter
9-
from .utils import get_active_app_pids, get_active_window_info
9+
from .utils import get_active_window_info, get_active_app_pids
1010

11-
__all__ = ["CpuLimiter", "get_active_app_pids", "get_active_window_info"], get_active_window_info
11+
__all__ = ["CpuLimiter", "get_active_window_info", "get_active_app_pids"]

cpulimiter/limiter.py

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,30 @@ def _limit_loop(self):
116116

117117
class CpuLimiter:
118118
"""Manages and applies CPU limits to one or more processes."""
119-
def __init__(self):
120-
self._limiters = {} # Stores {_ProcessLimiter object}
121-
self._process_info = {} # Stores info about the processes being limited
119+
def __init__(self, processes_to_limit: dict = None):
120+
"""
121+
Initializes the CpuLimiter.
122+
123+
Args:
124+
processes_to_limit (dict, optional): A dictionary where keys are process identifiers
125+
(name, pid, or window title part) and values are
126+
the limit percentage. If provided, automatically
127+
adds and starts limiting these processes.
128+
Example: {"chrome.exe": 95, 1234: 90}
129+
"""
130+
self._limiters = {} # Stores {pid: _ProcessLimiter object}
131+
self._process_info = {} # Stores {pid: info dict}
132+
133+
if processes_to_limit:
134+
for identifier, limit in processes_to_limit.items():
135+
# Determine the type of identifier and call add() accordingly
136+
if isinstance(identifier, int): # PID
137+
self.add(pid=identifier, limit_percentage=limit)
138+
elif isinstance(identifier, str) and (identifier.endswith(".exe") or "." in identifier): # Process Name
139+
self.add(process_name=identifier, limit_percentage=limit)
140+
elif isinstance(identifier, str): # Window Title
141+
self.add(window_title_contains=identifier, limit_percentage=limit)
142+
self.start_all()
122143

123144
def _find_pids_by_name(self, process_name):
124145
pids = []
@@ -162,6 +183,15 @@ def add(self, pid=None, process_name=None, window_title_contains=None, limit_per
162183
}
163184
self._limiters[p] = _ProcessLimiter(p, limit_percentage)
164185

186+
def remove(self, pid=None, process_name=None, window_title_contains=None):
187+
"""Removes a process from the limiter."""
188+
pids_to_remove = self._get_pids_for_criteria(pid, process_name, window_title_contains)
189+
for p in pids_to_remove:
190+
if p in self._limiters:
191+
self._limiters[p].stop()
192+
del self._limiters[p]
193+
del self._process_info[p]
194+
165195
def start(self, pid=None, process_name=None, window_title_contains=None):
166196
"""Starts limiting a specific process/group that has been added."""
167197
pids_to_start = self._get_pids_for_criteria(pid, process_name, window_title_contains)
@@ -186,6 +216,10 @@ def stop_all(self):
186216
for limiter in self._limiters.values():
187217
limiter.stop()
188218

219+
def shutdown(self):
220+
"""A convenient alias for stop_all()."""
221+
self.stop_all()
222+
189223
def get_active(self):
190224
"""Returns a list of actively limited processes."""
191225
return [info for pid, info in self._process_info.items() if self._limiters[pid].active]
@@ -202,3 +236,4 @@ def _get_pids_for_criteria(self, pid=None, process_name=None, window_title_conta
202236
if window_title_contains and info["window_title_contains"] == window_title_contains:
203237
found_pids.append(p)
204238
return found_pids
239+

examples/basic_usage.py

Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,29 @@
11
from cpulimiter import CpuLimiter
22
import time
3-
import psutil
43

5-
def find_pid_by_name(process_name):
6-
"""Helper function to find a PID by its name."""
7-
for proc in psutil.process_iter(['pid', 'name']):
8-
if proc.info['name'] == process_name:
9-
return proc.info['pid']
10-
return None
114

125
# --- Example Usage ---
136

147
# 1. Initialize the limiter
158
limiter = CpuLimiter()
169

17-
# 2. Find a process to limit (e.g., Notepad)
18-
# (You can open Notepad to test this)
19-
notepad_pid = find_pid_by_name("notepad.exe")
10+
app_name = "notepad.exe"
2011

21-
if notepad_pid:
22-
print(f"Found Notepad with PID: {notepad_pid}")
12+
# 3. Add the process to the limiter
13+
limiter.add(process_name=app_name, limit_percentage=95)
2314

24-
# 3. Add the process to the limiter
25-
limiter.add(pid=notepad_pid, limit_percentage=95)
15+
# 4. Start limiting
16+
print("Starting to limit Notepad for 15 seconds...")
17+
limiter.start(process_name=app_name)
2618

27-
# 4. Start limiting
28-
print("Starting to limit Notepad for 15 seconds...")
29-
limiter.start(pid=notepad_pid)
19+
# You can check the task manager to see the effect.
20+
time.sleep(15)
3021

31-
# You can check the task manager to see the effect.
32-
time.sleep(15)
22+
# 5. Stop limiting
23+
print("Stopping the limit.")
24+
limiter.stop(process_name=app_name)
3325

34-
# 5. Stop limiting
35-
print("Stopping the limit.")
36-
limiter.stop(pid=notepad_pid)
37-
38-
print("Limiting has been stopped.")
39-
else:
40-
print("Notepad is not running. Please open it and run the script again.")
26+
print("Limiting has been stopped.")
4127

4228
# --- Example with multiple processes ---
4329

examples/simple_limit.py

Lines changed: 41 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -16,65 +16,58 @@
1616
def main():
1717
print("🚀 Simple CPU Limiter Example")
1818
print("=" * 40)
19-
20-
# Initialize the limiter
21-
limiter = CpuLimiter()
22-
23-
# Add applications to limit
24-
# This will find all running instances and limit them
25-
print("📝 Adding applications to limit...")
26-
27-
# Limit Chrome to 10% CPU (90% limitation)
28-
limiter.add(process_name="chrome.exe", limit_percentage=90)
29-
print(" ✅ Added Chrome (chrome.exe) - 90% limitation")
30-
31-
# Limit Spotify to 5% CPU (95% limitation)
32-
limiter.add(process_name="spotify.exe", limit_percentage=95)
33-
print(" ✅ Added Spotify (spotify.exe) - 95% limitation")
34-
35-
# You can also limit by window title
36-
limiter.add(window_title_contains="YouTube", limit_percentage=85)
37-
print(" ✅ Added YouTube windows - 85% limitation")
38-
39-
print("\n🔄 Starting CPU limiting...")
19+
20+
# With the updated library, you can define and start the limits all in one step.
21+
# The keys are the process identifiers (name, PID, or window title substring)
22+
# and the values are the percentage to limit by.
23+
processes_to_limit = {
24+
"chrome.exe": 90, # Limit Chrome to 10% CPU (90% limit)
25+
"spotify.exe": 95, # Limit Spotify to 5% CPU (95% limit)
26+
"YouTube": 85 # Limit any window with "YouTube" in the title to 15% CPU
27+
}
28+
29+
print("📝 Initializing and starting limiter for:")
30+
for proc, limit in processes_to_limit.items():
31+
print(f" ✅ {proc} (limited by {limit}%)")
32+
33+
# Initialize the limiter and it will automatically start limiting the processes.
34+
limiter = CpuLimiter(processes_to_limit)
35+
36+
print("\n🔄 CPU limiting is now active...")
4037
print("💡 Check Task Manager to see the effect!")
4138
print("⌨️ Press Ctrl+C to stop\n")
42-
43-
# Start limiting all added processes
44-
limiter.start_all()
45-
39+
4640
try:
4741
# Let it run and show status every 10 seconds
48-
for i in range(6): # Run for 60 seconds total
42+
while True:
4943
time.sleep(10)
5044
active_limits = limiter.get_active()
51-
print(f"📊 Status update #{i+1}: {len(active_limits)} processes being limited")
52-
53-
if not active_limits:
54-
print("💡 No processes found to limit. Make sure the target applications are running.")
55-
45+
if active_limits:
46+
print(f"📊 Status: {len(active_limits)} processes are being actively limited.")
47+
else:
48+
print("💡 No target processes found. Make sure they are running.")
49+
break
50+
5651
except KeyboardInterrupt:
57-
print("\n⚠️ Stopping early due to user interrupt...")
58-
52+
print("\n⚠️ Stopping due to user interrupt...")
53+
5954
finally:
6055
print("🛑 Stopping all CPU limits...")
61-
limiter.stop_all()
56+
limiter.shutdown() # shutdown() is an alias for stop_all()
6257
print("✅ All limits removed. Applications restored to normal speed.")
6358

59+
6460
if __name__ == "__main__":
6561
import ctypes
6662
import sys
67-
68-
# Check for admin privileges
69-
try:
70-
is_admin = ctypes.windll.shell32.IsUserAnAdmin()
71-
except:
72-
is_admin = False
73-
74-
if not is_admin:
75-
print("🔐 This script requires Administrator privileges")
76-
print("🔄 Please run as Administrator and try again")
77-
input("Press Enter to exit...")
78-
sys.exit(1)
79-
80-
main()
63+
# check if the script is run with Administrator
64+
if ctypes.windll.shell32.IsUserAnAdmin():
65+
main()
66+
else:
67+
print("⚠️ This script requires Administrator privileges.")
68+
choice = input("Do you want to restart with admin rights? (y/n): ").strip().lower()
69+
if choice == 'y':
70+
print("🔄 Attempting to re-launch with elevation...")
71+
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)
72+
else:
73+
print("❌ Exiting. Please run as Administrator manually.")

0 commit comments

Comments
 (0)