简体   繁体   English

超时后停止阻塞 python 线程

[英]Stop a blocking python thread after timeout

I'm having an issue that is really difficult to find an already made solution for it.我遇到的问题很难找到已经制定的解决方案。

I'm running a new python thread that is then blocked by a socket connection (python-socketio) because it is waiting indefinitely for data.我正在运行一个新的 python 线程,该线程随后被套接字连接 (python-socketio) 阻塞,因为它无限期地等待数据。 But I need to close this thread after 5 minutes.但我需要在 5 分钟后关闭此线程。 I've tried to setup a timer that would close the thread with sys.exit() but I found that this was closing the timer thread itself.我试图设置一个计时器,用sys.exit()关闭线程,但我发现这是在关闭计时器线程本身。

Here is the code so far:这是到目前为止的代码:

class LiveMatches(commands.Cog):
    def __init__(self, client):
        self.client = client 

    def connect_to_scorebot(self, id):
        feed = MatchFeed(self.client)
        feed.main(id) # when this function is called, 
# it will block the newly created thread to receive the data with the socket

    def create_thread(self, id):
        # we create the thread and call launch_match that will connect to
        # the scorebot
        new_thread = threading.Thread(target=self.connect_to_scorebot, args=(id,))
        # start the thread
        new_thread.start()

A couple of options:几个选项:

  1. You can set a timeout on the the socket used in the thread so that it returns from blocking after a period of time.您可以在线程中使用的套接字上设置超时,以便它在一段时间后从阻塞中返回。
  2. Use select.select() with a timeout to poll a socket for data, periodically checking if the thread should exit.使用带有超时的select.select()来轮询套接字以获取数据,定期检查线程是否应该退出。

Example of #1: #1 的示例:

import threading
import socket
import select

# A server that echos only the first data received from a client
def server():
    s = socket.socket()
    s.bind(('',5000))
    s.listen()
    print('server: running')
    while True:
        c,a = s.accept()
        print('server: client connected')
        with c: # closes client socket when with block exits
            echoed = False
            while True:
                data = c.recv(1024)
                if not data: break
                if not echoed:
                    print('server: responding',data)
                    c.sendall(data)
                    echoed = True
        print('server: client disconnected')

def client():
    s = socket.socket()
    s.connect(('localhost',5000))
    with s: # closes client socket when with block exits
        try:
            s.settimeout(5) # 5-second timeout if no data received.
            print('client: send one')
            s.sendall(b'one')
            print('client: got',s.recv(1024))
            print('client: send two')
            s.sendall(b'two')
            print('client: got',s.recv(1024))  # this will timeout
        except socket.timeout:
            print('client: timed out')

# Start server thread.
# As a daemon, it will exit if main thread and client thread both exit.
threading.Thread(target=server,daemon=True).start()

t = threading.Thread(target=client)
t.start()
t.join() # wait for client thread to exit.
t = threading.Thread(target=client)
t.start()
t.join() # wait for client thread to exit.

Output: Output:

server: running
client: send one
server: client connected
server: responding b'one'
client: got b'one'
client: send two
client: timed out
server: client disconnected
client: send one
server: client connected
server: responding b'one'
client: got b'one'
client: send two
client: timed out

Note server didn't print that the second client disconnected.注意服务器没有打印第二个客户端断开连接。 Since it is a daemon thread, it was terminated when the main thread and client thread both exited, and didn't have time to recognize the client disconnected after timeout.由于是daemon线程,当主线程和client线程都退出时就终止了,超时没来得及识别client断开连接。 If you want cleaner exit behavior, don't use daemon threads.如果您想要更干净的退出行为,请不要使用守护线程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM