2201_75335496 2024-06-19 21:15 采纳率: 83.8%
浏览 3
已结题

python subprocess.Popen卡顿

正在编写一个IDE,使用subprocess.Popen时发现输出流会卡顿,请问为什么

def whileCheck():
    while True:
        if pypro.poll() != None:
            #改变按钮和菜单状态
            sb.config(state = tk.DISABLED)
            rb.config(state = tk.NORMAL)
            runfm.delete(0,1)
            runfm.add_command(label = "运行",command = partial(runPythonFile,"run"))
            runfm.add_command(label = "终止",command = partial(runPythonFile,"stop"),state = tk.DISABLED)
            cst.config(state = tk.NORMAL)
            cst.insert(tk.END,"\n\n--------------------Stop--------------------")
            cst.config(state = tk.DISABLED)
            cst.see(tk.END)
            print("---子进程结束---")
            return
def read_output(pipe,mod):
        print(f"StartReadOutput:mod={mod}")
        if mod == "err":
            cst.tag_configure(mod, foreground="red")
        else:
            cst.tag_configure(mod, foreground="black")
        while pypro.poll() is None:
            line = pipe.readline().strip().decode("utf-8") + "\n"
            if line:
                print(f"std{mod} >> {line}",end = "")
                #将输出写入到tk.text中
                cst.config(state = tk.NORMAL)
                cst.insert(tk.END,line,mod)
                cst.config(state = tk.DISABLED)
                cst.see(tk.END)
                win.update()
        pypro.stdout.close()
        print(f"\n---{mod}输出流结束---\n")
pypro = subprocess.Popen([f"{pythonRunningPath}\\python37\\python.exe",openFileDir["path"]],
                                         stdout = subprocess.PIPE,
                                         stderr = subprocess.PIPE,
                                         shell = False,
                                         cwd = os.path.dirname(openFileDir["path"])
t1 = threading.Thread(target=read_output, args=(pypro.stdout,"out"))
t2 = threading.Thread(target=read_output, args=(pypro.stderr,"err"))
threading.Thread(target = whileCheck).start()
t1.start()
t2.start()
  • 写回答

1条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-06-19 21:15
    关注

    引自免费微信小程序:皆我百晓生

    在使用subprocess.Popen处理实时输出流时遇到卡顿,通常是由几个常见的原因造成的,主要涉及线程、GUI更新以及文件读取的效率。针对你提供的代码,这里有几个建议和改进措施:

    1. 减少GUI更新频率

    GUI更新(通过调用win.update())是一个耗时操作,尤其是在主线程中频繁执行时。这可能导致其他线程的执行被阻塞,从而造成卡顿。考虑减少更新频率,例如仅当输出达到一定长度后再进行更新。

    2. 优化输出读取

    使用pipe.readline()在没有新数据时会阻塞,直到有新的输出或超时。这可能导致读取线程长时间阻塞,特别是在输出较慢的情况下。可以改用select.select()asyncio来实现非阻塞读取。

    3. 使用非阻塞IO

    下面是一个使用select.select()的示例,它允许我们检查文件描述符是否可读,而无需实际读取数据,从而避免了不必要的阻塞:

    import select
    
    def read_output(pipe, mod):
        print(f"StartReadOutput:mod={mod}")
        if mod == "err":
            cst.tag_configure(mod, foreground="red")
        else:
            cst.tag_configure(mod, foreground="black")
    
        while pypro.poll() is None:
            rlist, _, _ = select.select([pipe], [], [], 0.1)  # 0.1秒超时
            if rlist:
                line = pipe.readline().strip().decode("utf-8") + "\n"
                if line:
                    print(f"std{mod} >> {line}", end="")
                    # 将输出写入到tk.text中
                    cst.config(state=tk.NORMAL)
                    cst.insert(tk.END, line, mod)
                    cst.config(state=tk.DISABLED)
                    cst.see(tk.END)
                    # 只在必要的时候更新GUI
                    if len(line) > 50:  # 或者根据实际情况调整这个阈值
                        win.update()
    
    # 其他代码保持不变...
    

    4. 考虑使用异步IO

    对于更复杂的场景,尤其是当需要处理多个并发事件时,使用asyncio可能更为合适。不过,这通常意味着整个应用程序结构需要相应的调整,以便于异步编程。

    5. 线程同步

    确保所有对GUI的修改都在主GUI线程中进行,因为Tkinter不是线程安全的。可以使用mainloop()中的after()方法或Queue来安全地更新GUI组件。

    通过上述建议,你应该能够显著减少卡顿现象,使IDE的响应更加流畅。如果仍有性能瓶颈,可能需要进一步分析具体场景下的I/O行为和CPU使用情况。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录

报告相同问题?

问题事件

  • 系统已结题 7月6日
  • 已采纳回答 6月28日
  • 创建了问题 6月19日

悬赏问题

  • ¥15 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 java 的protected权限 ,问题在注释里
  • ¥15 这个是哪里有问题啊?