停止客户端线程

时间:2015-05-07 09:06:29

标签: python multithreading sockets

我使用下面的类听大约20个udp端口。关于如何阻止它,这个课程有一个问题。因为我在stop方法中加入线程所以我必须等待最多一秒才能使每个类停止,因为recv的超时时间为1秒。你会如何推荐我解决这个问题?

class UpdClient(threading.Thread):     

    def __init__(self,port):
        super(UpdClient, self).__init__()
        self.port = port
        self.finished = False
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.bind(('225.0.0.10', self.port))
        self.sock.settimeout(1)

    def run(self):
        while not self.finished:
            try:
                message = self.sock.recv(4096)
                print("*")
            except socket.timeout:
                continue

    def stop(self):
        self.finished = True
        if self.is_alive(): 
            self.join()
        print("Exiting :" + str(self.port))

2 个答案:

答案 0 :(得分:3)

您可以采取一项简单的方法来改善这种情况:将stop功能拆分为两个独立的功能,如下所示:

def stop(self):
    self.finished = True
    print("Stopping :" + str(self.port))

def wait(self):
    self.stop()
    if self.is_alive(): 
        self.join()
    print("Exiting :" + str(self.port))

然后这样做:

for t in threads:
    t.stop()
for t in threads:
    t.wait()

使用20个线程,这可以将平均停止时间从大约10秒减少到大约1.1秒。

但是如果你想要比这更好,比如保证1秒,或者平均时间低于1秒,那么就没有好的,简单的方法。一些可能不好和/或困难的选项包括:

  • send根据User的建议向您自己的套接字发送消息。如果你的代码知道如何处理"垃圾"消息,或者如果您的协议使添加新消息类型变得简单,可以很容易地与"真实"消息,这应该唤醒你的线程,以便很快关闭它们。
  • close从客户端线程下面的套接字。在某些平台上,这会导致recv立即失败(当然,您希望except处理此问题)。在其他情况下,它会立即导致它(你已经处理过)。有些平台都不会发生,它只会继续阻塞。因此,您确实需要在您关注的每个平台上进行测试。 *
  • self.daemon = True。然后你可以通过退出而不加入它们来硬杀死所有线程。具有所暗示的所有缺点。
  • 完全重写您的应用以使用单线程反应器或多线程反应器(理想情况下间接地,通过类似asynciotwistedgevent ......),而不是每个客户一个帖子。
  • 将等待的1秒等待更改为等待时间不超过100毫秒(或者退出时间可以接受多长时间)。
  • 只需接受1秒的退出时间。

*在我的头脑中,我相信Windows保证错误,Linux保证错误或继续阻止但通常继续阻止,BSD不保证任何但通常继续阻止,除了通常的EOF之外,SysV不保证任何东西。但不要相信我的头脑;测试你关心的平台。

答案 1 :(得分:-1)

在Windows下,添加以下内容:

def stop(self):
    self.sock.close()
    # ...

这会产生错误:

OSError: [WinError 10004] A blocking operation was interrupted by a call to WSACancelBlockingCall
线程中的