【问题标题】:Python : how to stop a thread that's waiting for a .recv()Python:如何停止等待 .recv() 的线程
【发布时间】:2014-08-22 03:58:42
【问题描述】:

我正在运行这个线程:

def run(self):
    while 1:
        msg = self.connection.recv(1024).decode()

我希望当我像这样关闭 Tkinter 窗口时可以结束这个线程:

self.window.protocol('WM_DELETE_WINDOW', self.closeThreads)

def closeThreads(self):
    self.game.destroy()
    #End the thread

不能使用 thread._close(),因为它已被弃用并且 python 3.4 不允许它。

【问题讨论】:

  • 试试看你的connection对象是否有非阻塞的recv方法。这样,您可以定期轮询它的数据并检查您在 closeThreads 方法中设置的退出标志。如果设置了标志,则跳出循环并从run 函数返回。如果您的connection 对象是socket,您可以调用self.connection.setblocking(0) 使其成为非阻塞对象。

标签: python multithreading


【解决方案1】:

对于这个问题,我看到的唯一真正令人满意的解决方案是不允许您的线程在 recv() 中阻塞。相反,将套接字设置为非阻塞并在 select() 中设置线程块。在 select() 中阻塞的好处是,当多个套接字中的任何一个变为可读取时,您可以告诉 select() 返回,这将我们带到下一部分:作为设置线程的一部分,创建第二个套接字(可以是本地连接的 TCP 套接字,例如 socketpair 提供的,或者是在端口上侦听来自 localhost 的数据包的 UDP 套接字)。当您的主线程希望您的网络线程消失时,您的主线程应该向该套接字发送一个字节(或者在 TCP 情况下,主线程可以关闭其套接字对的末端)。这将导致 select() 在该套接字上返回准备读取,并且当您的网络线程意识到套接字被标记为准备读取时,它应该立即退出响应。

这样做的好处是它可以在所有操作系统上运行良好,总是立即做出反应(与轮询/超时解决方案不同),当网络空闲时占用零额外的 CPU 周期,并且没有任何讨厌的多线程环境中的副作用。缺点是它使用了几个额外的套接字,但这通常没什么大不了的。

【讨论】:

  • 在python中,IO是阻塞的。时期。尝试在套接字上调用read(),然后在一段时间后终止该线程。所以“不阻止”不是一个选项。
  • 我在 Python 中使用非阻塞套接字已经很多年了,效果很好。
【解决方案2】:

两种解决方案:

1) 不要停止线程,当进程以sys.exit() 退出时让它死掉

2) 使用“die now”标志启动线程。 Event 类专门设计用于从另一个线程发出信号。

以下示例启动一个线程,该线程连接到服务器。任何数据都被处理,如果父线程通知线程退出,它就会退出。作为一项额外的安全功能,我们有一个警报信号来杀死所有东西,以防万一出现失控。

来源

import signal, socket, threading

class MyThread(threading.Thread):
    def __init__(self, conn, event):
        super(MyThread,self).__init__()
        self.conn = conn
        self.event = event

    def handle_data(self):
        "process data if any"
        try:
            data = self.conn.recv(4096)
            if data:
                print 'data:',data,len(data)
        except socket.timeout:
            print '(timeout)'

    def run(self):
        self.conn.settimeout(1.0)
        # exit on signal from caller
        while not self.event.is_set():
            # handle any data; continue loop after 1 second
            self.handle_data()
        print 'got event; returning to caller'


sock = socket.create_connection( ('example.com', 80) )
event = threading.Event()

# connect to server and start connection handler
th = MyThread(conn=sock, event=event)

# watchdog: kill everything in 3 seconds
signal.alarm(3)

# after 2 seconds, tell data thread to exit 
threading.Timer(2.0, event.set).start()

# start data thread and wait for it
th.start()
th.join()

输出

(timeout)
(timeout)
got event; returning to caller

【讨论】:

  • 这不会停止线程等待.recv()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多