V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
coolfan
V2EX  ›  Python

我代码动了,我不写了? while 循环莫名其妙运行俩次,找个赛博驱魔师

  •  1
     
  •   coolfan · 56 天前 · 4508 次点击
    这是一个创建于 56 天前的主题,其中的信息可能已经有所发展或是发生改变。

    代码在下面

    # pt 文件,pytorch 运行
    
    import sys
    from time import time
    from ultralytics import YOLO
    import cv2
    
    # Load a model
    model = YOLO("yolov8n.pt")  # load an official model
    model = model.to("cuda")
    
    video_path = "C:/Users/username/Desktop/学姐向你发出了约会邀请❤怦然心动❤.1542979357.mp4"
    cap = cv2.VideoCapture(video_path)
    
    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    total_time = 0
    while True:
        ret, frame = cap.read()
        if not ret:
            break  # Exit the loop if no more frames are available
        # frame = cv2.resize(frame, (640, 640))
        start_time = time()
        results = model(frame, verbose=False, classes=[0])
        total_time += time() - start_time
        cv2.imshow("frame", results[0].plot())
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
        # 打印进度
        finished_frames = int(cap.get(cv2.CAP_PROP_POS_FRAMES))
        sys.stdout.write("\r 进度: %.2f %%" % (finished_frames / total_frames * 100))
        sys.stdout.flush()
        # results = model(frame, verbose=False,classes=[0]) CPU FPS:  14.687764775223318
        # results = model(frame, verbose=False,classes=[0]) FPS:  64.14847574515913
        # results = model(frame, verbose=False) FPS:  60.23244793078058
    
        # 2024-05-22 23:32:05 FPS:  60.21048703460454 CUDA
    
    print("\nFPS: ", total_frames / total_time)
    

    这段代码在 22 号还是正常的,输出就是“进度:”滚动,然后最后输出一行 FPS ,cv2.imshow 那三行还没写。

    刚才去洗了个澡,加上了 cv2.imshow 那三行,又跑了一次,输出变成了

    python yolo-torch.py
    C:\Users\username\Documents\code\project\.venv\Lib\site-packages\torch\nn\modules\conv.py:456: UserWarning: Plan failed with a cudnnException: CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR: cudnnFinalize Descriptor Failed cudnn_status: CUDNN_STATUS_NOT_SUPPORTED (Triggered internally at ..\aten\src\ATen\native\cudnn\Conv_v8.cpp:919.)
      return F.conv2d(input, weight, bias, self.stride,
    进度: 99.85 %
    FPS:  75.04395604987724
    进度: 99.85 %
    FPS:  21.148407567206448
    

    终端先是滚动一边进度,非常快,然后打印了一行 FPS ,但是这个时候 cv2 的 imshow 没有展示出来, 在第一个 FPS 打印完之后,又开始滚动输出“进度:”,这次 cv2.imshow 会正常显示,然后最后输出一个 FPS 。

    但是这俩个 FPS 都和 22 号的值差了不少,22 号的时候一直稳定 60 上下

    然后我注释了 # 打印进度下面的三行,输出变成了

    python yolo-torch.py
    C:\Users\username\Documents\code\project\.venv\Lib\site-packages\torch\nn\modules\conv.py:456: UserWarning: Plan failed with a cudnnException: CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR: cudnnFinalize Descriptor Failed cudnn_status: CUDNN_STATUS_NOT_SUPPORTED (Triggered internally at ..\aten\src\ATen\native\cudnn\Conv_v8.cpp:919.)
      return F.conv2d(input, weight, bias, self.stride,
    进度: 99.85 %
    FPS:  72.13356492043005
    
    FPS:  21.089225686164987
    

    为什么啊。我代码一行一行看过去,也看不出来为什么 while 循环会运行俩次,第一次还是我昨天的版本?

    30 条回复    2024-05-24 09:23:04 +08:00
    freakxx
        1
    freakxx  
       56 天前   ❤️ 4
    video_path = "C:/Users/username/Desktop/学姐向你发出了约会邀请❤怦然心动❤.1542979357.mp4"

    代码用这种命名,发生啥 bug 我都不觉得奇怪。
    Amose2024
        2
    Amose2024  
       56 天前
    While True 是会一直运行的,没有适当的退出机制何谈运行两次?说明你的"break"条件,有时不成立,有时成立。
    Amose2024
        3
    Amose2024  
       56 天前
    另外,任何程序,不包括注释,请尽量避免使用中文
    fkdtz
        4
    fkdtz  
       56 天前
    @freakxx
    请教这种命名咋了?
    hefish
        5
    hefish  
       56 天前   ❤️ 1
    会不会是 & 要用 and 代替一下?
    artiga033
        6
    artiga033  
       56 天前 via Android
    这种情况一般我会选择进行单步调试
    malaohu
        7
    malaohu  
       56 天前
    首先没看你的代码。前几天排查有点类似的情况。
    Flask + 多个线程服务 启动

    main 入口 打印日志 莫名执行 2 次

    原来是开启了调试模式
    dream4ever
        8
    dream4ever  
       56 天前
    @malaohu 还能这样,React 的 useEffect 是不是从这里学的,哈哈哈哈
    SunsetShimmer
        9
    SunsetShimmer  
       56 天前 via Android   ❤️ 1
    @freakxx 作为一个临时的路径,填什么都是有可能的。只要不明确影响代码(转义之类的问题),这种表述没有意义。
    lx01xsz
        10
    lx01xsz  
       56 天前 via iPhone
    这不像是被执行了两次,从第二次进度输出还是 99.85% 就可以看出
    显示较低的 FPS (21.xxx) 应该是 `cv2.imshow` 导致的
    虽然你用了 `sys.stdout.flush()`,但可能 OpenCV 某些操作会引入额外的 delay
    woodfizky
        11
    woodfizky  
       56 天前   ❤️ 1
    先把代码放函数里,调用的地方放在__main__里调用,这样能排除这个文件被 import 的时候代码被执行一次的情况。

    其他的如果是第三方的东西去跑你这个 py ,那就要看第三方是不是有什么配置。
    woodfizky
        12
    woodfizky  
       56 天前   ❤️ 17
    另外评论区有些人不知道是不是对中文编码有 ptsd 。

    都 2024 年了,在 windows 平台,用天然支持 utf8 的 python ,读个本地文件用中文路径,能出啥问题呢?
    出问题在读文件那步就已经发现了,不知道在害怕什么。
    Rorysky
        13
    Rorysky  
       56 天前
    @woodfizky 水平太差,不了解语言的发展,可能还停留在 py2 的年代
    xubingok
        14
    xubingok  
       56 天前
    @freakxx 严格来说..这不叫代码的命名.
    这是代码的执行目标的命名,没有任何问题,也无法控制.
    cyrivlclth
        15
    cyrivlclth  
       56 天前
    @freakxx 人中文的是字符串,楼上哪些喷的啥意思?字符串都不能输入中文了?又不是变量名用中文
    LDa
        16
    LDa  
       56 天前   ❤️ 1
    想要知道这个 mp3 是啥
    idealhs
        17
    idealhs  
       56 天前   ❤️ 3
    @freakxx 感觉你啥也不懂,命名是 video_path 。字符串处理不好就别干了,你这样写出来的软件是那种要求文件和目录不能包含中文和特殊字符的玩意。
    krixaar
        18
    krixaar  
       56 天前
    @freakxx #1 一个文件路径,只要能读到能出啥 bug ?
    peasant
        19
    peasant  
       56 天前   ❤️ 4
    sijue
        20
    sijue  
       56 天前
    在两个 if 中打印,哪个位置打印两次就是第二次循环没拦住
    AFuture
        22
    AFuture  
       55 天前
    你想问 为什么加了 cv2.imshow 导致 FPS 降低么?
    应该是 waitKey 时同步的关系,等待输入的时候,进程卡在那,但是 FPS 的统计时长是增加的。
    AFuture
        23
    AFuture  
       55 天前
    @AFuture 无视无视 。。
    DIMOJANG
        24
    DIMOJANG  
       55 天前
    @sijue #20 不像,仔细观察楼主贴的 log 里打印两次的百分比是一样的
    Anarchy
        25
    Anarchy  
       55 天前
    @woodfizky #12 Python 是支持可是 OpenCV 可不一定支持
    lostsummer
        26
    lostsummer  
       55 天前   ❤️ 1
    你将主要运行代码放到

    if __name__ == "__main__":

    下面。

    我没有 windows 环境去验证,但我猜你是遇到了 python 多进程在 windows 环境的一个常见问题。( cv2.imshow 开窗口时可能会 fork 一个子进程)

    原因解释看下: https://zhuanlan.zhihu.com/p/616746911 #七、
    artiga033
        27
    artiga033  
       55 天前 via Android   ❤️ 2
    @Amose2024 都 2024 年了,对于一个支持 Unicode 标识符的编程语言,您猜怎么着,我不但能用中文,甚至还能用 emoji 和阿拉伯语
    Freakr
        28
    Freakr  
       55 天前
    @artiga033 Python 里面不用 emoji 作为标识符吧
    vivisidea
        29
    vivisidea  
       55 天前
    @lostsummer 我也是这个猜测,估计是起了进程,又运行了一遍

    可以试试在 while True: 前面加上打印当前进程号的代码即可验证

    import os

    # 获取当前进程 ID
    current_process_id = os.getpid()

    # 打印当前进程 ID
    print(f"当前进程 ID: {current_process_id}")
    purplemystic
        30
    purplemystic  
       55 天前
    @Amose2024 中文注释也遇到过问题, C++里面, 中文注释导致编译失败
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4648 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 03:57 · PVG 11:57 · LAX 20:57 · JFK 23:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.