2013-06-12 2 views
5

Я применяю тайм-аут для блока кода с помощью модуля multiprocessing. Похоже, что при вводе определенного размера возникает ошибка:«WindowsError: Access denied» при вызове Process.terminate

WindowsError: [Error 5] Access is denied 

Я могу воспроизвести эту ошибку следующим кодом. Обратите внимание, что код завершен с '467,912,040', но не с '517,912,040'.

import multiprocessing, Queue 

def wrapper(queue, lst): 
    lst.append(1) 
    queue.put(lst) 
    queue.close() 

def timeout(timeout, lst): 
    q = multiprocessing.Queue(1) 
    proc = multiprocessing.Process(target=wrapper, args=(q, lst)) 
    proc.start() 
    try: 
     result = q.get(True, timeout) 
    except Queue.Empty: 
     return None 
    finally: 
     proc.terminate() 
    return result 

if __name__ == "__main__": 
    # lst = [0]*417912040 # this works fine 
    # lst = [0]*467912040 # this works fine 
    lst = [0] * 517912040 # this does not 
    print "List length:",len(lst) 
    timeout(60*30, lst) 

Выход (включая ошибки):

List length: 517912040 

Traceback (most recent call last): 
    File ".\multiprocessing_error.py", line 29, in <module> 
    print "List length:",len(lst) 
    File ".\multiprocessing_error.py", line 21, in timeout 
    proc.terminate() 
    File "C:\Python27\lib\multiprocessing\process.py", line 137, in terminate 
    self._popen.terminate() 
    File "C:\Python27\lib\multiprocessing\forking.py", line 306, in terminate 
    _subprocess.TerminateProcess(int(self._handle), TERMINATE) 
WindowsError: [Error 5] Access is denied 

Могу ли я не разрешается прекращать процесс определенного размера?

Я использую Python 2.7 для Windows 7 (64 бит).

+1

Я не думаю, что вы разозлили python ... но его большой список, который вы хотите перенести, и вы, вероятно, запустили время, пока дочерний процесс был в странном состоянии (возможно, даже не начался). Просто мой список занял 70 секунд в моей системе. Вы можете распечатать дескриптор, когда завершится сбой, и посмотреть, существует ли процесс. Возможно, вы могли бы немного поспать и попробовать еще раз. – tdelaney

+1

Похоже, проблема связана с вызовом 'len (lst)', который может быть вызван тем, что 'queue' был поврежден. Предупреждение о том, что это может случиться, выделено в 'terminate()' [documentation] (http://docs.python.org/2/library/multiprocessing.html?highlight=terminate#multiprocessing.Process.terminate). – martineau

ответ

5

Хотя я до сих пор неясно относительно точной причины проблемы, у меня есть некоторые дополнительные замечания, а также обходной путь.

Обходным решением.

Добавление блока try-except в предложение finally.

finally: 
    try: 
     proc.terminate() 
    except WindowsError: 
     pass 

Это также, как представляется, решение, достигнутое в родственный (?) Вопрос отвечал here on GitHub (вы, возможно, придется прокрутить вниз немного).

Наблюдения.

  1. Эта ошибка зависит от размера объекта передается процессу/очереди, но это не связано с выполнением самого процесса. В OP процесс завершается до истечения таймаута.
  2. proc.is_alive возвращает True до и после выполнения proc.terminate() (который затем выбрасывает WindowsError). Через секунду или два, proc.is_alive() возвращает False, а второй вызов proc.terminate() преуспевает.
  3. Принуждает основную нить спать time.sleep(1) в блоке finally также предотвращает выброс WindowsError. Спасибо, комментарий @ tdelaney в OP.
  4. Мое лучшее предположение, что proc в процессе освобождения памяти (? Или что-то сравнимое), будучи убитым ОС (завершение выполнения), когда вызов proc.terminate() пытается его снова убить.