2011-10-08 66 views
4

下面的代碼用於將上傳的圖片同步到另一個地方。它工作,但經過一段時間(大約10天)後,該服務無法使用,顯示錯誤:'filedescriptor在select()'中超出範圍,但重新啓動服務可解決問題。「當使用python的rsync子進程時,select()中的filedescriptor超出範圍」

# 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(),它有1024個文件描述符的限制,甚至epoll可用)

+0

終於我刪除PIPE重定向時,Popen,並檢查'proc.returnval',它似乎工作。 – limboy

回答

2

您可以手動關閉文件描述符。撥打communicate後,請致電proc.stderr.close()proc.stdout.close()

+2

這是否真的解決了這個問題?我查看了'subprocess'的來源,看起來這些描述符應該在'_communicate'中自動關閉。 –

+0

我同意,他們*應該*。但出於某種原因,你的情況並非如此。 –

+0

感謝您的建議,我會嘗試一下,看看它是否有效。 – limboy

0

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.

可能的修復:使用Python 2.7+,或反向移植使用poll的代碼。