“文件描述符超出 select() 范围”当使用带有 rsync 的 python 子进程时

发布于 2024-12-08 19:06:31 字数 1549 浏览 0 评论 0原文

下面的代码用于将上传的图片同步到另一个地方。它可以工作,但在一段时间(大约10天)后,该服务无法使用,显示错误:'filedescriptor out of range in select()',但重新启动服务解决了问题。

# sync.py

def sync_file(source_pic, hashval, retry_num=3):

    pic_path = os.path.join(gen_dir(hashval), os.path.split(source_pic)[1])
    filename = tempfile.mkstemp()[1]
    with open(filename, 'w') as f:
        f.write(pic_path)

    for sync_path in options.sync_paths:
        try_num = 0
        rsync_cmd = ['rsync','-au', '--files-from='+filename, options.pic_path, sync_path]

        while try_num < retry_num:
            proc = subprocess.Popen(rsync_cmd,stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            stdout_value, stderr_value = proc.communicate()

            if len(stderr_value) != 0:
                logger.error('sync failed: %s' % stderr_value)
                try_num = try_num + 1
                #raise UploadException('sync failed')
            else:
                break

    os.remove(filename)

日志信息:

File "/path/to/sync.py", line 25, in sync_file
    stdout_value, stderr_value = proc.communicate()
File "/usr/lib/python2.6/subprocess.py", line 691, in communicate
    return self._communicate(input)
File "/usr/lib/python2.6/subprocess.py", line 1211, in _communicate
    rlist, wlist, xlist = select.select(read_set, write_set, [])
    ValueError: filedescriptor out of range in select()

是否有未关闭的文件描述符导致错误?看来子进程没有关闭文件描述符,所以当它运行1024次时,文件描述符超出了范围。 (我们使用的是python 2.6,子进程被迫使用select.select(),即使epoll可用,它也有1024个文件描述符的限制)

the code below is used to sync uploaded picture to another place. it works, but after a period of time(about 10 days), the service is unusable , showing error: 'filedescriptor out of range in select()', but restart service solves the problem.

# sync.py

def sync_file(source_pic, hashval, retry_num=3):

    pic_path = os.path.join(gen_dir(hashval), os.path.split(source_pic)[1])
    filename = tempfile.mkstemp()[1]
    with open(filename, 'w') as f:
        f.write(pic_path)

    for sync_path in options.sync_paths:
        try_num = 0
        rsync_cmd = ['rsync','-au', '--files-from='+filename, options.pic_path, sync_path]

        while try_num < retry_num:
            proc = subprocess.Popen(rsync_cmd,stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            stdout_value, stderr_value = proc.communicate()

            if len(stderr_value) != 0:
                logger.error('sync failed: %s' % stderr_value)
                try_num = try_num + 1
                #raise UploadException('sync failed')
            else:
                break

    os.remove(filename)

log info:

File "/path/to/sync.py", line 25, in sync_file
    stdout_value, stderr_value = proc.communicate()
File "/usr/lib/python2.6/subprocess.py", line 691, in communicate
    return self._communicate(input)
File "/usr/lib/python2.6/subprocess.py", line 1211, in _communicate
    rlist, wlist, xlist = select.select(read_set, write_set, [])
    ValueError: filedescriptor out of range in select()

are there unclosed file descriptors that cause the error? it seems subprocess doesn't close file descriptor, so when it runs 1024 times, the file descriptor is out of range. (we are using python 2.6, subprocess is forced to use select.select() which has a limit of 1024 file descriptors even epoll is available)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

腹黑女流氓 2024-12-15 19:06:31

https://bugzilla.redhat.com/show_bug.cgi?id=609020

在 Python 2.7 之前,使用 ulimit -n 启用的程序
与大量子进程的通信仍然可以监控
一次只有1024个文件描述符,导致异常:

ValueError:文件描述符超出 select() 范围

这是由于子进程模块使用了select系统调用。
该模块现在使用 poll 系统调用,消除了此限制。

可能的修复:使用 python 2.7+,或使用 poll 反向移植代码。

https://bugzilla.redhat.com/show_bug.cgi?id=609020

Prior to Python 2.7, programs that used ulimit -n to enable
communication with large numbers of subprocesses could still monitor
only 1024 file descriptors at a time, which caused an exception:

ValueError: filedescriptor out of range in select()

This was due to the subprocess module using the select system call.
The module now uses the poll system call, removing this limitation.

possible fix: use python 2.7+, or backport the code using poll.

偏爱你一生 2024-12-15 19:06:31

您可以手动关闭文件描述符。调用communicate后,调用proc.stderr.close()proc.stdout.close()

You can manually close the file descriptors. After calling communicate, call proc.stderr.close() and proc.stdout.close().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文