2013-06-12 11 views
5

Applico un timeout per un blocco di codice utilizzando il modulo multiprocessing. Sembra che con alcuni input di dimensioni, viene sollevato il seguente errore:"WindowsError: accesso negato" alla chiamata Process.terminate

WindowsError: [Error 5] Access is denied 

Posso replicare questo errore con il seguente codice. Si noti che il codice viene completato con '467,912,040' ma non con '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) 

L'uscita (compreso l'errore):

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 

non mi è permesso di interrompere un processo di una certa dimensione?

Sto usando Python 2.7 su Windows 7 (64 bit).

+1

Non penso che tu abbia fatto arrabbiare il pitone ... ma è un elenco di grandi dimensioni che desideri trasferire e probabilmente sei scaduto mentre il processo figlio si trovava in uno stato strano (forse nemmeno iniziato). Il solo decapaggio della tua lista ha richiesto 70 secondi sul mio sistema. È possibile stampare l'handle quando il terminate fallisce e vedere se il processo esiste. Forse potresti dormire un po 'e riprovare. – tdelaney

+1

Sembra che il problema abbia qualcosa a che fare con la chiamata 'len (lst)' che potrebbe essere dovuta al fatto che la 'coda' è stata danneggiata. C'è un avvertimento su ciò che potrebbe accadere evidenziato in 'terminate()' [documentation] (http://docs.python.org/2/library/multiprocessing.html?highlight=terminate#multiprocessing.Process.terminate). – martineau

risposta

5

Mentre sono ancora incerto riguardo alla causa precisa del problema, ho alcune osservazioni aggiuntive e una soluzione alternativa.

Soluzione alternativa.

Aggiunta di un blocco try-except nella clausola finally.

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

Questo sembra anche essere la soluzione adottata nella un relativo (?) Problema postato here on GitHub (potrebbe essere necessario scorrere verso il basso un po ').

Osservazioni.

  1. Questo errore dipende dalle dimensioni dell'oggetto passato al processo/coda, ma non è legato alla esecuzione del processo stesso. Nell'OP, il processo viene completato prima della scadenza del timeout.
  2. proc.is_alive restituisce True prima e dopo l'esecuzione di proc.terminate() (che quindi genera l'errore Windows). Uno o due secondi dopo, proc.is_alive() restituisce False e una seconda chiamata a proc.terminate() ha esito positivo.
  3. Forzare il thread principale in stop time.sleep(1) nel blocco finally impedisce anche il lancio di WindowsError. Grazie, il commento di @tdelaney nell'OP.
  4. La mia ipotesi migliore è che proc stia liberando memoria (?, O qualcosa di simile) mentre viene ucciso dal sistema operativo (dopo aver completato l'esecuzione) quando la chiamata a proc.terminate() tenta di ucciderlo di nuovo.