如何用Python将磁盘IO与网络IO转换为百分比(仿Windows任务管理器)
Hey there! Let's work through your problem step by step. I get that you've already grabbed the raw byte counts from psutil.disk_io_counters() and psutil.net_io_counters(), but figuring out percentages and getting per-device data can be tricky. Here's how to fix both issues:
First: Get Per-Device/Per-Network Interface Data
The default calls to those functions return system-wide totals, not per-instance stats. To get individual disk or network interface data, you just need to add a simple parameter:
- For disks: Use
psutil.disk_io_counters(perdisk=True)— this returns a dictionary where keys are disk names (likePhysicalDrive0on Windows) and values aresdiskioobjects with read/write bytes, counts, etc. - For networks: Use
psutil.net_io_counters(pernic=True)— this returns a dictionary of network interfaces (likeEthernetorWi-Fi) mapped tosnetioobjects with recv/send bytes.
Note: On Windows, you might see some virtual disks (like system recovery partitions) or loopback interfaces — you can filter those out if you don't need them by cross-referencing with
psutil.disk_partitions()for disks, or checking interface names for networks.
Second: Calculate IO Usage Percentages
Percentages in Task Manager represent current IO rate divided by the device's maximum theoretical bandwidth, multiplied by 100. Here's the breakdown:
- Take two samples of IO data with a small time gap (e.g., 1 second).
- Calculate the byte difference between the two samples to get the amount of data transferred in that window.
- Divide by the time gap to get the per-second rate (convert bytes to MB for readability).
- Divide that rate by the device's maximum bandwidth (e.g., a 1Gbps network card = ~125 MB/s; an SSD might do 500 MB/s read) and multiply by 100 to get the percentage.
Full Working Code Example
Here's a script that mimics Task Manager's real-time IO monitoring:
import psutil import time def get_disk_max_bandwidth(disk_name): # Replace with your disk's actual max read/write speeds (MB/s) # You can look up your disk specs, or use WMI to fetch dynamically on Windows if "PhysicalDrive0" in disk_name: return {"read": 550, "write": 500} # Example NVMe SSD speeds return {"read": 120, "write": 100} # Example HDD speeds def get_network_max_bandwidth(iface_name): # Replace with your interface's max speed (MB/s) # 1Gbps = ~125 MB/s, 10Gbps = ~1250 MB/s, etc. if "Ethernet" in iface_name or "Wi-Fi" in iface_name: return 125 # 1Gbps example return 10 # Skip virtual interfaces with low bandwidth def monitor_io(interval=1): # Initial sample to compare against prev_disk_io = psutil.disk_io_counters(perdisk=True) prev_net_io = psutil.net_io_counters(pernic=True) time.sleep(interval) while True: # Grab current IO stats curr_disk_io = psutil.disk_io_counters(perdisk=True) curr_net_io = psutil.net_io_counters(pernic=True) # Calculate Disk IO Usage print("\n=== Disk IO Usage ===") for disk, curr_stats in curr_disk_io.items(): if disk not in prev_disk_io: continue # Skip disks that appeared mid-monitoring prev_stats = prev_disk_io[disk] # Convert byte differences to MB/s read_rate = (curr_stats.read_bytes - prev_stats.read_bytes) / (1024 * 1024) / interval write_rate = (curr_stats.write_bytes - prev_stats.write_bytes) / (1024 * 1024) / interval # Calculate percentage against max bandwidth max_bw = get_disk_max_bandwidth(disk) read_pct = min((read_rate / max_bw["read"]) * 100, 100) if max_bw["read"] > 0 else 0 write_pct = min((write_rate / max_bw["write"]) * 100, 100) if max_bw["write"] > 0 else 0 print(f"Disk {disk}:") print(f" Read: {read_rate:.2f} MB/s ({read_pct:.1f}%)") print(f" Write: {write_rate:.2f} MB/s ({write_pct:.1f}%)") # Calculate Network IO Usage print("\n=== Network IO Usage ===") for iface, curr_stats in curr_net_io.items(): if iface not in prev_net_io: continue prev_stats = prev_net_io[iface] # Convert byte differences to MB/s recv_rate = (curr_stats.bytes_recv - prev_stats.bytes_recv) / (1024 * 1024) / interval send_rate = (curr_stats.bytes_sent - prev_stats.bytes_sent) / (1024 * 1024) / interval # Calculate percentage against max bandwidth max_bw = get_network_max_bandwidth(iface) recv_pct = min((recv_rate / max_bw) * 100, 100) if max_bw > 0 else 0 send_pct = min((send_rate / max_bw) * 100, 100) if max_bw > 0 else 0 print(f"Interface {iface}:") print(f" Receive: {recv_rate:.2f} MB/s ({recv_pct:.1f}%)") print(f" Send: {send_rate:.2f} MB/s ({send_pct:.1f}%)") # Update previous stats for next loop prev_disk_io = curr_disk_io prev_net_io = curr_net_io time.sleep(interval) if __name__ == "__main__": try: monitor_io() except KeyboardInterrupt: print("\nMonitoring stopped.")
Key Tips:
- Dynamic Bandwidth Detection: The example uses hardcoded speeds, but on Windows you can use the
wmilibrary to fetch real disk/network capabilities dynamically (e.g., queryWin32_DiskDrivefor disk speeds orWin32_NetworkAdapterfor network bandwidth). - Filtering Devices: Add checks to skip virtual disks or unused network interfaces (like
Loopback Pseudo-Interface) to clean up the output. - Precision: Adjust the
intervalparameter to change refresh speed — Task Manager uses ~1 second by default.
内容的提问来源于stack exchange,提问作者M. P

