我想问一下,tkinter 做多线程爬虫,让他停止该怎么做 quit 和 exit 都是直接退出程序

    thread = threading.Thread(target=self.threading_run);
    thread.start()

    pass
def threading_run_s(self):

    print("-----------****************++++++++")
    print(url)
    for xb in range(10):
        print(xb)
        output.Output(str(xb))
        time.sleep(10)
        
阅读 4.7k
2 个回答

python 没有现成的方法可以强制结束线程,建议改用 multiprocessing 模块。


强制结束线程可通过 ctypes 调用系统 API 实现,以 windows 系统为例,如下

# -*- coding: utf-8 -*-
import threading
import time
from datetime import datetime


def term_thread(thread_id):
    # 强制结束线程
    import os
    if os.name == "nt":
        # windows 系统
        # 注意:线程结束后 threading.Thread 没有任何提示。
        import ctypes
        h = ctypes.windll.kernel32.OpenThread(1, 0, thread_id)
        assert h != 0
        r = ctypes.windll.kernel32.TerminateThread(h, 0xff)
        assert r != 0
    else:
        # TODO
        raise NotImplementedError


def run_thread():
    while 1:
        time.sleep(1)
        print('{}'.format(datetime.now()))


def main():
    t = threading.Thread(target=run_thread)
    t.start()

    time.sleep(3)
    term_thread(t.ident)

    # 强制结束线程导致 join() 永远不会返回
    # t.join()


if __name__ == '__main__':
    main()

Python的threading类没有提供退出方法,退出方法需要自己实现.
这涉及到两个问题:

  • 线程通信:子线程怎么知道父线程让子线程退出.
  • 退出的实现:子线程知道之后该怎么退出

线程通信

threading提供了Event这个类,实际上这个类就是一个信号,可以比较方便的实现线程间通信.因为多线程运行在一个进程中,也可以自己定义一个类来传递信号.略过不表.

# coding:utf-8
import threading
import time

signal = threading.Event()  # 定义一个信号


def worker(signal, *args, **kwargs):
    """子线程核心函数

    Arguments:
        signal {threading.Event} -- 接收的信号
    """
    # 如果信号为False,则执行任务
    while not signal.isSet():
        # 执行工作
        print("working")
        time.sleep(1)

    print("exiting")
    # 信号为True时,退出子线程
    exit()


t = threading.Thread(target=worker, args=(signal,))
t.start()
time.sleep(2)
print(u"发送退出信号")
signal.set()
time.sleep(1.5)
print(u"当前子线程的状态为{}".format(t.isAlive()))
time.sleep(1)

输出

working
working
发送退出信号
exiting
当前子线程的状态为False

在子线程内部调用exit(),是退出子线程而不是退出主线程,调用位置的问题.

退出线程

退出线程有很多办法,不过核心就是判断信号的状态.这就需要在worker流程控制中加好判断点位.要明确退出不是指令发出去立刻就会执行,而是处理信号的代码发现了信号改变才会停止worker,这个是需要自己实现的.
比如上方代码在signal.isSet()发生改变之后,跳出了while循环,实际上worker已经结束了,exit方法是为了增加可读性的,完全没必要加.
通过任何方法结束线程都可以,运行完毕或者手动exit都可以

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题