python.multiprocessing e “FATAL ERROR (INFADI) MISSING DIRECTORY”

9

Ao tentar fazer o multiprocessamento com o arcpy, ocasionalmente, encontro esse erro:

FATAL ERROR (INFADI)
MISSING DIRECTORY

Não tenho idéia do que está desencadeando esse erro e ele trava o processo python, tornando impossível obter um rastreio nele. Isso ocorre ao gravar a saída raster final de um modelo de som demorado.

Às vezes é acompanhado por um erro

Unable to write BND file for %TEMP%\ras####

Onde% Temp é analisado corretamente e #### é um número aleatório de 4 dígitos. Isso é incomum porque cada processo possui seu próprio espaço de trabalho, onde é onde a maioria dos arquivos deve ser gravada.

O problema não são os dados de entrada ... Posso executar o programa novamente nas entradas com falha e ele será executado corretamente.

blord-castillo
fonte
Voltarei a este em breve, mas agora tenho que trabalhar em um modelo diferente.
Blord-castillo 5/10

Respostas:

6

Aqui estão algumas coisas para verificar:

Você está usando cursores? Você está liberando eles? Você está tentando reutilizar objetos em diferentes processos? Você está compartilhando o mesmo local temporário? Você está fazendo no processamento de memória?

Em geral, o arcpy é apenas um invólucro em torno dos objetos com e qualquer tipo de multiprocessamento será complicado.

Jamie
fonte
4

Descobri que esse problema surge quando o arcpy.env.workspace e o arcpy.env.scratchWorkspace são iguais para dois processos diferentes. O Arc grava quase todos os rasters intermediários no espaço de trabalho (ou espaço de trabalho de rascunho) no formato ESRI GRID. Não é possível gravar duas rasters ESRI GRID no mesmo diretório ao mesmo tempo devido à estrutura de pseudo-banco de dados do formato (a pasta info contém chaves exclusivas para cada varredura).

Evitei esse erro atribuindo espaço de trabalho exclusivo e espaço de trabalho a zero para cada processo usando uma pasta temporária tempfile.mkdtemp.

jonah
fonte
Eu já uso espaços de trabalho exclusivos, mas vou verificar novamente se o scratchWorkspace também é exclusivo. Acho que não, uma vez que está gravando no diretório% TEMP%.
blord-castillo
Jonah está certo. Estou processando milhares de rasters em um único diretório em 5 threads simultâneos; definir um espaço de trabalho de rascunho exclusivo para cada um é a única solução que funcionou para mim. A saída para pastas exclusivas, como alguns recomendam, apenas cria mais trabalho para mais tarde ... eventualmente, quero todas elas no mesmo diretório.
Tom
Que dor nas costas! Usar o espaço de trabalho exclusivo de rascunho com o multiprocessamento funcionou, mas meu deus, gerenciar as pastas extras e depois tentar excluí-las com bloqueios de arco é ridículo!
D_C
3

Eu encontrei isso também e ainda não encontrei uma correção de som. Minha solução é 1) para garantir que a tarefa de multiprocessamento seja robusta o suficiente para verificar se as tarefas estão concluídas ou não e criar uma nova lista de tarefas. 2) agende dois scripts para serem lançados a cada 10 a 15 minutos. Um script contém um comando para eliminar os processos python selecionados e o segundo relança o script de multiprocessamento desejado. Essencialmente, isso atualiza o pool de multiprocessamento. O script kill é algo como isto:

def read_pid():
    inFile = open("E:/temp/pid.csv")
    for line in inFile:
        pid = str(line)
    inFile.close()
    return pid

def kill():
    if os.path.exists("E:/temp/pid.csv")==True:
        pid = read_pid()
        PROCESS_TERMINATE=1
        handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE,False,pid)
        ctypes.windll.kernel32.TerminateProcess(handle,-1)
        ctypes.windll.kernel32.CloseHandle(handle)
    else:
        return

Cada lançamento do script desejado eu tenho que escrever seu PID em um CSV.

metasequoia
fonte
2

Descobri que estava recebendo o erro INFADI ao tentar fazer com que vários threads / núcleos salvassem e modificassem rasters em uma pasta. A atribuição de uma subpasta a cada tarefa para saídas parece resolver o problema. Acredito que o problema tenha a ver com várias leituras / gravações em arquivos periféricos associados à varredura (por exemplo, a pasta "info"). Agora também uso as seguintes precauções:

import arcpy,multiprocessing,random

def run(foo,c):
    tempFolder = os.path.join("Z:/temp/",'temp_%s'%(str(c)))
    if not os.path.exists(tempFolder): os.mkdir(tempFolder)
    arcpy.env.scratchWorkspace = tempFolder
    arcpy.env.Workspace = tempFolder

    # create unique object in memory, run task, then delete unique object in memory
    tempMem = str(rnd)
    try:arcpy.Delete_management(tempMem)
    except:pass

    <tasks> #output to appropriate subfolder

    arcpy.Delete_management(tempMem)

if __name__ == '__main__':
    cores = 3
    pool = multiprocessing.Pool(cores)
    count = 0
    for foo in bar:
        pool.apply_async(run,(foo,c))
        count +=1
    pool.close()
    pool.join()
metasequoia
fonte
Parece que nunca recebo erros ao gravar vários GRIDs na mesma pasta por meio de vários threads. O único problema parece ser que isso diminui o processamento e invalida virtualmente o encadeamento, pois ele grava apenas uma varredura por vez.
Tom