You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中Socket Timeout后线程未正常清理,线程号持续增长的解决方法

问题分析与解决方案

你的代码存在几处导致线程无法正常清理的问题,同时线程ID递增本身是Python的正常行为,但如果是活跃线程数量持续增长,可通过以下方式修复:

1. 捕获Socket超时异常,保证线程正常退出

原代码中recv设置超时后,超时会抛出socket.timeout异常,直接终止线程,导致后续的client_socket.close()和循环退出逻辑无法执行,线程资源无法正常释放。修改on_new_client函数,添加异常捕获:

def on_new_client(client_socket, addr):
    try:
        while True:
            client_socket.settimeout(10)
            try:
                data = client_socket.recv(1024).decode('utf-8')
            except socket.timeout:
                print(f"Connection from {addr} timed out")
                break
            client_socket.settimeout(None)
            send = "GOK"
            client_socket.send(send.encode())

            if not data:
                print(f'Disconnected from {addr}')
                break
            print("Adr and data", addr, data)
    finally:
        # 无论正常退出还是异常,都确保关闭socket
        client_socket.close()
        print(f"Connection from {addr} closed")

2. 设置守护线程,避免资源残留

将子线程设置为守护线程,当主线程退出时,所有守护线程会自动终止,防止主线程退出后还有残留线程占用资源。创建线程时添加daemon=True:

thread = Thread(target=on_new_client, args=(c, addr), daemon=True)

注:原代码中thread.join()放在while True循环外,永远不会执行,可直接删除。

3. 使用线程池限制并发数(可选优化)

如果并发连接较多,无限制创建线程会耗尽服务器资源,建议用concurrent.futures.ThreadPoolExecutor管理线程,自动回收线程资源:

import socket
from concurrent.futures import ThreadPoolExecutor

def on_new_client(client_socket, addr):
    try:
        while True:
            client_socket.settimeout(10)
            try:
                data = client_socket.recv(1024).decode('utf-8')
            except socket.timeout:
                print(f"Connection from {addr} timed out")
                break
            client_socket.settimeout(None)
            send = "GOK"
            client_socket.send(send.encode())

            if not data:
                print(f'Disconnected from {addr}')
                break
            print("Adr and data", addr, data)
    finally:
        client_socket.close()
        print(f"Connection from {addr} closed")

def main():
    host = '127.0.0.1'
    port = 4001

    s = socket.socket()
    s.bind((host, port))
    s.listen(5)
    print(f"Server listening on {host}:{port}")

    # 创建线程池,设置最大并发线程数
    with ThreadPoolExecutor(max_workers=10) as executor:
        while True:
            c, addr = s.accept()
            print("New connection from:", addr)
            executor.submit(on_new_client, c, addr)

if __name__ == '__main__':
    main()

关于线程号持续增加的说明

Python中线程ID是全局递增的,即使旧线程已被销毁回收,新创建的线程ID也会继续使用下一个数字,这是正常行为,不代表线程资源未被清理。你可以通过threading.enumerate()查看当前活跃线程数量,若数量未持续增长,说明线程已正常清理。

内容的提问来源于stack exchange,提问作者Sathish

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 03:46:13