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
123abcdf11345
V2EX  ›  Python

多线程的一点问题

  •  
  •   123abcdf11345 · 2022-02-19 17:03:19 +08:00 · 3829 次点击
    这是一个创建于 1041 天前的主题,其中的信息可能已经有所发展或是发生改变。
    def isRunning(process_name): 
            try:
                process=len(os.popen('tasklist | findstr '+process_name).readlines())
                if process >=1 :
                    return True
                else:
                    return False
            except:
                print("程序错误")
                return False
    
    def task_killer():
            while 1:
                if isRunning('Taskmgr.exe'):
                    os.system('taskkill /IM Taskmgr.exe')
                time.sleep(1)
    

    以上代码用来干掉 Taskmgr.exe 进程,使用 Threading 模块的 Thread 实现多线程

    t1 = threading.Thread(target=task_killer)
    t1.start()
    

    现在想问怎么终止这个线程,t1.join 没用,还会堵塞,t1.join(1)也没用,google 找了以下代码也没用

    def _async_raise(tid, exctype):
        """raises the exception, performs cleanup if needed"""
        tid = ctypes.c_long(tid)
        if not inspect.isclass(exctype):
            exctype = type(exctype)
        res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
        if res == 0:
            raise ValueError("invalid thread id")
        elif res != 1:
            # """if it returns a number greater than one, you're in trouble,
            # and you should call it again with exc=NULL to revert the effect"""
            ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
            raise SystemError("PyThreadState_SetAsyncExc failed")
     
    def stop_thread(thread):
        '''强制关闭某一个线程'''
        _async_raise(thread.ident, SystemExit)
    

    谢谢!

    12 条回复    2022-02-23 17:06:49 +08:00
    BrettD
        1
    BrettD  
       2022-02-19 17:40:45 +08:00
    你在线程里面死循环,join 当然会阻塞了
    ClericPy
        2
    ClericPy  
       2022-02-19 18:06:23 +08:00
    因为用的 OS thread 基本没有太粗暴的外部 kill 方式 (这也是我喜欢协程的原因, 虽然协程很多时候比线程费劲太多. 有时候真想外部 kill 就用进程当线程也可以)

    早年间 Google 上搜 how to kill thread python 一大把原因和各种花哨操作实际并没什么卵用

    所以只能线程内部自己结束标识或者设置守护线程什么的
    ho121
        3
    ho121  
       2022-02-19 20:53:59 +08:00 via Android
    zhttp
        4
    zhttp  
       2022-02-19 22:05:12 +08:00
    这种一般是弄个标志吧,每次循环检查一下。
    ysc3839
        5
    ysc3839  
       2022-02-19 22:50:08 +08:00   ❤️ 1
    怀疑是 X-Y Problem https://coolshell.cn/articles/10804.html
    为什么要 kill taskmgr.exe ?为什么杀进程还用调用命令行工具这么低级的方法,不直接调用 API ?为什么要从外部终止这个线程?用个变量让线程自己停止不行吗?
    beastk
        6
    beastk  
       2022-02-20 00:06:27 +08:00 via iPhone
    没什么好办法,试试 func_timeout 吧,超时就退出,注意会增加近一半多的线程
    hallDrawnel
        7
    hallDrawnel  
       2022-02-20 00:24:59 +08:00
    python 的多线程就是这么难搞。我自己的小项目直接放弃,用多进程,然后就可以很舒适的中断了。
    haoliang
        8
    haoliang  
       2022-02-20 01:07:15 +08:00
    可以用 threading.Event 来做。 我来给个具体示例,通过 ctrl-c 触发 signal interrupt 退出程序。

    这事看不出 python 的多线程难搞;没有提供主动终止线程的原因,我想有这个原因:线程与同进程的其他线程共享资源,如果不能做 cleanup 就被终止,会出现 fd 泄漏之类的问题; 而进程不同,操作系统会兜底

    ```
    #!/usr/bin/env python3

    import signal
    import time
    from threading import Event, Thread


    def killer(stop: Event):
    while True:
    if stop.is_set():
    print("killer: canceled")
    break
    print("killer: working")
    time.sleep(1)


    def main():
    stop = Event()

    def handle_sigint(*args):
    stop.set()

    signal.signal(signal.SIGINT, handle_sigint)

    th = Thread(target=killer, args=[stop])
    th.start()
    th.join()

    print("main thread exiting")


    if __name__ == "__main__":
    main()
    ```
    yingxiangyu
        9
    yingxiangyu  
       2022-02-20 01:42:10 +08:00
    换进程,如果出现 pickle 报错,就用 pathos import pathos

    Process = pathos.helpers.mp.Process
    yolee599
        10
    yolee599  
       2022-02-20 16:33:00 +08:00
    task_killer 里不要 while(1),要 while (quit_flag),你要结束线程的时候先置 quit_flag 为 0 ,再 join
    009694
        11
    009694  
       2022-02-21 08:43:38 +08:00 via iPhone
    从外部去 kill 一个毫无准备的线程 这本来就是很邪恶的做法。。为什么要提供这种机制 就是为了防止又菜又爱钻空子的人去用 最后变成很多人都在用
    18870715400
        12
    18870715400  
       2022-02-23 17:06:49 +08:00
    你的 while 1 没有退出的标志肯定会一直执行下去的呀。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3119 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 13:13 · PVG 21:13 · LAX 05:13 · JFK 08:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.