分叉:关闭所有打开的套接字。

4

我正在使用multiprocessing.Pool.map,它会fork当前进程。

据我了解,默认情况下,所有文件描述符包括套接字都会从主进程复制到fork出的子进程中。主进程本身是一个Web服务器(使用CherryPy),因此这会对开放的端口等造成破坏。fork出的进程只是在服务器使用的某个库中执行一些CPU密集型数值计算,与Web / Socket部分无关。

有没有一种简单的方法可以自动关闭新进程中的所有套接字?或者避免fork CherryPy服务器的问题的另一种方法?

使用CherryPy 3.2.2,Python 2.7;必须在Linux和OS X上工作。


懒惰的方法是在打开任何套接字之前创建进程池。 - Sven Marnach
不幸的是,在pool.map()调用时,我需要所有内存的“当前”快照...只是不包括套接字 :) - user124114
2个回答

4

POSIX没有提供一种合理的方法来列出或关闭一系列文件描述符。

因此,我们必须循环遍历整个范围(如从3到1023),逐个关闭文件描述符。

或者,如果我们有一个/proc文件系统,我们可以读取/ proc / self / fd中打开文件描述符的列表,只关闭这些文件描述符。 这比关闭所有可能的文件描述符更快。

import os

def close_files(fd_min=3, fd_max=-1):
    if os.path.exists('/proc/self/fd'):
        close_files_with_procfs(fd_min, fd_max)
    else:
        close_files_exhaustively(fd_min, fd_max)

def close_files_exhaustively(fd_min=3, fd_max=-1):
    import resource
    fd_top = resource.getrlimit(resource.RLIMIT_NOFILE)[1] - 1
    if fd_max == -1 or fd_max > fd_top:
        fd_max = fd_top
    for fd in range(fd_min, fd_max+1):
        try:
            os.close(fd)
        except OSError:
            pass

def close_files_with_procfs(fd_min=3, fd_max=-1):
    for nm in os.listdir("/proc/self/fd"):
        if nm.startswith('.'):
            continue
        fd = int(nm)
        if fd >= fd_min and (fd_max == -1 or fd < fd_max):
            try:
                os.close(fd)
            except OSError:
                pass

def timereps(reps, func):
    from time import time
    start = time()
    for i in range(0, reps):
        func()
    end = time()
    return (end - start) / reps

print "close_files: %f" % timereps(100, lambda: close_files())
print "close_files_exhaustively: %f" % timereps(100, lambda: close_files_exhaustively())
print "close_files_with_procfs: %f" % timereps(1000, lambda: close_files_with_procfs())

在我的系统上:

$ python ./close_fds.py 
close_files: 0.000094
close_files_exhaustively: 0.010151
close_files_with_procfs: 0.000039

1

还可以使用psutil库列出当前进程打开的所有连接。以下代码将关闭所有连接,但您可能需要筛选出感兴趣的连接:

import psutil, os

p = psutil.Process()
for c in p.connections(kind='inet'):
   os.close(c.fd)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接