在执行以下代码时,我尝试用lsof -U | wc -l
监视打开的Unix套接字文件的数量:
>>> import zmq
# 1375 Unix socket files
>>> c = zmq.Context()
# 1377 Unix socket files
>>> s = c.socket(zmq.PUSH)
# 1383 Unix socket files
>>> s.close()
# 1381 Unix socket files
>>> c.destroy()
# 1375 Unix socket files
那是为什么?我希望在连接套接字时打开一个TCP / IPC套接字文件,但是在连接之前这些文件呢?
似乎它们都是“ STREAM”类型:
有关重现此问题的有用脚本,请参见@gdlmx的答案。
如果您使用Conda安装pyzmq
,似乎一切正常。但是,我仍然想知道如果将pyzmq
与pip
一起安装时为什么它不起作用,我将考虑使用标准的方式来安装软件包。
复制步骤:
使用Conda:
conda create -n foo python=3.6
conda activate foo
pip install pyzmq
python test_script.py
使用Python的venv
:
python3.6 -m venv venv
source ./venv/bin/activate
pip install pyzmq
python test_script.py
答案 0 :(得分:4)
我建议使用普通python或ipython(无控制台)重新运行测试。还请使用lsof -p <pid>
将计数限制为单个进程,以排除来自计算机其他进程(测试中的那些1375 Unix套接字文件)的不必要干扰。
这是一个简单的测试脚本:
import os
pid = os.getpid()
count=0
def lsof():
global count
count += 1
print(count,':')
os.system("lsof -p {0:d} 2>/dev/null | grep -E 'unix|IPv4|IPv6'".format(pid)) # -U doesn't work togeter with -p option
# Alternatively, you can use "lsof -U 2>/dev/null | grep -E {0:d}"
# but only unix socket file will be listed.
import zmq
c = zmq.Context();lsof()
tcp = c.socket(zmq.PUSH);lsof()
unix = c.socket(zmq.PUSH);lsof()
print('--- To bind ---')
tcp.bind('tcp://127.0.0.1:19413');lsof()
unix.bind('ipc://filename');lsof()
print('--- To close ---')
tcp.close();lsof()
unix.close();lsof()
以下是我的环境中的测试结果(python 3.6.6,pyzmq 17.1.2,带有CentOS 7中的Anaconda)。
1 :
2 :
3 :
--- To bind ---
4 :
ZMQbg/1 284018 gdlmx 13u IPv4 49443178 0t0 TCP localhost:19413 (LISTEN)
5 :
ZMQbg/1 284018 gdlmx 13u IPv4 49443178 0t0 TCP localhost:19413 (LISTEN)
ZMQbg/1 284018 gdlmx 14u unix 0xffff9cd6c5bf4800 0t0 49443204 filename
--- To close ---
6 :
ZMQbg/1 284018 gdlmx 14u unix 0xffff9cd6c5bf4800 0t0 49443204 filename
7 :
我使用python和ipython运行脚本并获得了相同的结果。
最后,仅在调用socket.bind
时打开套接字文件或网络端口。在我的测试过程中,python / ipython进程没有打开其他套接字。
响应PO的更新:
异常(意外)行为可能是由PyPI上pyzmq软件包中捆绑的预构建二进制文件引起的。 pip install pyzmq
将从PyPI下载该distribution tar ball,该文件包含以下预编译的二进制文件:
zmq/backend/cython:
_device.so _proxy_steerable.so constants.so error.so socket.so
_poll.so _version.so context.so message.so utils.so
zmq/.libs:
libzmq-39117701.so.5.2.1 libsodium-72341b7d.so.23.2.0
为了与尽可能多的Linux操作系统兼容,这些二进制文件是在称为manylinux的docker环境中的非常老的OS(CentOS 5)中构建的。
Anaconda使用另一种方法来预构建二进制文件,并将所有依赖项包含在conda/envs
文件夹中。因此,它们的二进制文件是在相对最新的环境中构建的。
我使用上述脚本在CentOS 7计算机上测试了PyPI的二进制文件。我可以确认ZeroMQ打开了一些“后台”套接字(上下文创建后有2个套接字,第一次创建套接字后有8个套接字)。尽管下面的测试表明它们用于ZeroMQ的内部机制的线程间通信,但最好直接询问PyPI package的维护者。
您也可以尝试强制pip
/ setuptools
为您的操作系统构建ZeroMQ:
sudo yum install libzmq3-devel # RHEL-based
pip install --no-use-wheel pyzmq
# Use `--no-binary :all:` instead of `--no-use-wheel` in pip >= 10.0.0
如果您想要的话,这可能会摆脱后台套接字。
ZeroMQ内部使用多个线程进行IO操作。线程数可以通过IO_THREADS进行配置。我发现此数字会影响使用中的套接字数。用
进行测试num_io_threads = int(sys.argv[1])
c = zmq.Context()
c.set(zmq.IO_THREADS,num_io_threads)
s = c.socket(zmq.PUSH)
lsof()
您会发现number_of_sockets
= 6 + 2 * num_io_threads
。因此,我假设来自PyPI的ZeroMQ二进制文件在内部使用套接字在主线程和工作线程/ IO线程之间进行线程间通信。