Python运行时硬盘一直有写入如何排查和解决

现在在学习 Python,发现一件有件事不是太明白,我的 Python 程序在运行时一直有写硬盘的操作,又没有读取,我全部的操作在内存里完成,并没有涉及到文件读写,这个写硬盘来源在哪里?
Python 程序主要作用是截图并识别文字
用到三个:win32API、OpenCV 和 pytesseract
win32API 是用来截图,
OpenCV 是把截图转换成二值图
pytesseract 识别二值图,return 出识别结果。

在程序运行时,发现 win32 每次截图,win8.1 系统资源管理器都显示有 50kb/s 左右的写入操作,时间不到一秒。我对 win32API 截图操作以 200ms 间隔迭代了两万多次,发现硬盘一直在写入,速度大概在 53kb/s,但是在中间没有任何读取操作。

如果我的程序完整运行,在迭代过程中,发现资源管理器会显示硬盘写入速度在 170kb/s 左右。

不明白的,这个写入究竟写的是什么内容,我全部操作都在内存里完成,不涉及到写文件操作。
Python运行时硬盘一直有写入如何排查和解决


6 回复

跟图片有关的缓存都是写在 temp 里的可以自己翻源码


这个问题我遇到过,排查硬盘写入可以从这几个方向入手:

1. 先定位是哪个进程在写

import subprocess
import sys

# Windows用Process Monitor,Linux/Mac用iotop
if sys.platform == "win32":
    print("建议下载Process Monitor查看磁盘活动")
else:
    try:
        subprocess.run(["sudo", "iotop", "-o", "-P"], check=False)
    except:
        print("安装iotop: sudo apt install iotop")

2. 检查Python程序自身的文件操作 常见问题代码:

# 问题示例:频繁写入日志
import logging

logging.basicConfig(
    level=logging.DEBUG,
    filename='app.log',  # 持续写入
    filemode='a'         # 追加模式
)

# 改为按大小或时间轮转
from logging.handlers import RotatingFileHandler
handler = RotatingFileHandler('app.log', maxBytes=1024*1024, backupCount=5)

3. 检查第三方库的缓存

# 很多库会缓存数据到磁盘
import tempfile
print(f"临时目录: {tempfile.gettempdir()}")

# 清理可能的大量缓存文件
import shutil, os
temp_dir = tempfile.gettempdir()
for item in os.listdir(temp_dir):
    if item.startswith("python_"):  # 示例匹配模式
        path = os.path.join(temp_dir, item)
        try:
            if os.path.isfile(path):
                os.unlink(path)
            elif os.path.isdir(path):
                shutil.rmtree(path)
        except Exception as e:
            print(f"无法删除 {path}: {e}")

4. 数据库操作检查

# SQLite自动提交可能导致频繁写入
import sqlite3

# 坏例子
conn = sqlite3.connect('test.db')  # 默认autocommit=False但某些操作会触发
conn.execute("INSERT INTO table VALUES (?)", [data])  # 每次执行都可能写盘

# 改进:显式事务批量操作
conn = sqlite3.connect('test.db', isolation_level=None)  # 或手动控制
cursor = conn.cursor()
cursor.execute("BEGIN")
for data in large_dataset:
    cursor.execute("INSERT INTO table VALUES (?)", [data])
cursor.execute("COMMIT")

5. 使用监控工具定位

# 简单监控脚本
import psutil
import time

def monitor_io(pid=None, interval=2):
    """监控指定进程或所有Python进程的IO"""
    if pid:
        p = psutil.Process(pid)
        print(f"监控进程 {pid} ({p.name()})")
    else:
        # 监控所有Python进程
        python_procs = [proc for proc in psutil.process_iter() 
                       if 'python' in proc.name().lower()]
    
    while True:
        if pid:
            io = p.io_counters()
            print(f"写字节数: {io.write_bytes / 1024:.1f}KB")
        time.sleep(interval)

# 使用前安装: pip install psutil

快速排查步骤:

  1. 用系统工具(iotop/Process Monitor)找到具体进程
  2. 检查程序中的文件操作、日志配置
  3. 查看临时目录和缓存
  4. 数据库操作是否过于频繁

建议先确定是程序问题还是依赖库问题。

win32api 代码如下:
import win32gui
import win32ui
hwnd = win32gui.FindWindow(None, windowname)
wDC = win32gui.GetWindowDC(hwnd)
dcObj=win32ui.CreateDCFromHandle(wDC)
cDC=dcObj.CreateCompatibleDC()
dataBitMap = win32ui.CreateBitmap()
dataBitMap.CreateCompatibleBitmap(dcObj, w, h)
cDC.SelectObject(dataBitMap)
cDC.BitBlt((0,0),(w, h) , dcObj, (0,0), win32con.SRCCOPY)
#dataBitMap.SaveBitmapFile(cDC, bmpfilenamename)
我在这里就把 pycdc 转换成了 numpy,保存在变量里,在后面代码运行后,就 return 这个变量出去。
# Free Resources
dcObj.DeleteDC()
cDC.DeleteDC()
win32gui.ReleaseDC(hwnd, wDC)
win32gui.DeleteObject(dataBitMap.GetHandle())

非计算机专业,没有系统学过编程,对这些不是太明白。我用过 pillow 截图,这个要 50ms,速度不够快,win32API 只要 10ms,用 pillow 而这个也有写硬盘操作。像这种缓存,有没有办法避免它写,如果不想它写,该如何解决?

你去翻翻 pytesseract 的源码,有些使用他是调用 tesseract.exe 的,那样的话需要先把图片写入硬盘再让 exe 读取

谢了老哥

回到顶部