вилка: закройте все открытые розетки - PullRequest
4 голосов
/ 02 апреля 2012

Я использую multiprocessing.Pool.map, который разветвляет текущий процесс.

Насколько я понимаю, по умолчанию все файловые дескрипторы , включая сокеты , копируются из основного процесса при разветвлении.Главный процесс сам по себе является веб-сервером (использующим cherrypy ), так что это приводит к хаосу с открытыми портами и т. Д. Разветвленные процессы на самом деле делают только некоторые загруженные ЦП числовые вещи внутри одного избиблиотеки, которые использует сервер - ничего общего с частью web / socket.

Существует ли простой способ автоматически закрывать все сокеты в новых процессах?Или другой способ избежать проблем с разветвлением сервера CherryPy?

Использование CherryPy 3.2.2, Python 2.7;должен работать на Linux и OS X.

1 Ответ

4 голосов
/ 08 августа 2012

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
...