pangao1990 / PPX

基于Python和JavaScript,一键生成macOS、Windows和Linux平台客户端应用程序
https://blog.pangao.vip/docs-ppx/
GNU Affero General Public License v3.0
232 stars 39 forks source link

python多线程导致一直开启新的socket #53

Closed shengguo closed 2 months ago

shengguo commented 2 months ago

您好,我遇到一个问题,python多线程导致一直开启新的socket,有什么办法可以解决吗? 我这边socket是不能关闭的,希望保留一个socket的长连接。下面的错误信息中laddr应该是我本地的应答端口,一直在被开启新的 C:\python\Lib\threading.py:982: ResourceWarning: unclosed <socket.socket fd=2416, family=2, type=1, proto=0, laddr=('192.168.58.149', 51963), raddr=('192.168.58.2', 20004)> self._target(*self._args, self._kwargs) ResourceWarning: Enable tracemalloc to get the object allocation traceback C:\python\Lib\threading.py:982: ResourceWarning: unclosed <socket.socket fd=2404, family=2, type=1, proto=0, laddr=('192.168.58.149', 51966), raddr=('192.168.58.2', 20004)> self._target(*self._args, *self._kwargs) ResourceWarning: Enable tracemalloc to get the object allocation traceback C:\python\Lib\threading.py:982: ResourceWarning: unclosed <socket.socket fd=2416, family=2, type=1, proto=0, laddr=('192.168.58.149', 51967), raddr=('192.168.58.2', 20004)> self._target(self._args, self._kwargs) ResourceWarning: Enable tracemalloc to get the object allocation traceback C:\python\Lib\threading.py:982: ResourceWarning: unclosed <socket.socket fd=2404, family=2, type=1, proto=0, laddr=('192.168.58.149', 51969), raddr=('192.168.58.2', 20004)> self._target(*self._args, self._kwargs) ResourceWarning: Enable tracemalloc to get the object allocation traceback C:\python\Lib\threading.py:982: ResourceWarning: unclosed <socket.socket fd=2416, family=2, type=1, proto=0, laddr=('192.168.58.149', 51971), raddr=('192.168.58.2', 20004)> self._target(*self._args, *self._kwargs) ResourceWarning: Enable tracemalloc to get the object allocation traceback C:\python\Lib\threading.py:982: ResourceWarning: unclosed <socket.socket fd=2396, family=2, type=1, proto=0, laddr=('192.168.58.149', 51972), raddr=('192.168.58.2', 20004)> self._target(self._args, self._kwargs) ResourceWarning: Enable tracemalloc to get the object allocation traceback C:\python\Lib\threading.py:982: ResourceWarning: unclosed <socket.socket fd=2408, family=2, type=1, proto=0, laddr=('192.168.58.149', 51973), raddr=('192.168.58.2', 20004)> self._target(*self._args, *self._kwargs) ResourceWarning: Enable tracemalloc to get the object allocation traceback C:\python\Lib\threading.py:982: ResourceWarning: unclosed <socket.socket fd=2412, family=2, type=1, proto=0, laddr=('192.168.58.149', 51975), raddr=('192.168.58.2', 20004)> self._target(self._args, **self._kwargs) ResourceWarning: Enable tracemalloc to get the object allocation traceback

pangao1990 commented 2 months ago

你好,没有源码,单纯从这个报错信息,我也没有更好的办法。于是我问了ChatGPT,以下是它给出的答案,希望可以帮到你。

为了避免每次线程开启新 socket,你可以尝试以下几种解决方案: 1、使用一个全局的 socket 连接:将 socket 对象定义为全局变量或通过共享对象在多个线程中使用,以确保所有线程复用同一个 socket。

import socket
import threading

# 创建一个全局的 socket 连接
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.58.2', 20004))

def handle_connection():
    # 在每个线程中使用全局 socket 进行操作
    s.sendall(b"Hello, server")
    data = s.recv(1024)
    print(f"Received: {data}")

threads = []
for i in range(5):
    t = threading.Thread(target=handle_connection)
    threads.append(t)
    t.start()

for t in threads:
    t.join()

# 当不再需要时可以手动关闭 socket
s.close()

2、确保正确管理 socket 生命周期:如果必须每个线程创建新的 socket,确保在不需要时正确关闭 socket,避免资源泄露。

import socket
import threading

def handle_connection():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('192.168.58.2', 20004))
    try:
        s.sendall(b"Hello, server")
        data = s.recv(1024)
        print(f"Received: {data}")
    finally:
        # 确保 socket 在操作完成后被关闭
        s.close()

threads = []
for i in range(5):
    t = threading.Thread(target=handle_connection)
    threads.append(t)
    t.start()

for t in threads:
    t.join()

3、使用连接池:通过第三方库 socketpool 或者自己实现一个简单的 socket 连接池,多个线程可以从连接池中获取可用的 socket,避免频繁创建和销毁 socket。

4、使用 tracemalloc 追踪资源泄露:你也可以按照错误提示启用 tracemalloc 模块,追踪 socket 资源泄露的具体代码位置,方便定位问题。

import tracemalloc

tracemalloc.start()
shengguo commented 2 months ago

可能是我使用exec执行代码段导致的问题,这个issue可以关闭了,谢谢