Maximizando o uso da CPU

9

Meu script está cruzando linhas com polígonos. É um processo longo, pois existem mais de 3000 linhas e mais de 500000 polígonos. Eu executei do PyScripter:

# Import
import arcpy
import time

# Set envvironment
arcpy.env.workspace = r"E:\DensityMaps\DensityMapsTest1.gdb"
arcpy.env.overwriteOutput = True

# Set timer
from datetime import datetime
startTime = datetime.now()

# Set local variables
inFeatures = [r"E:\DensityMaps\DensityMapsTest.gdb\Grid1km_Clip", "JanuaryLines2"]
outFeatures = "JanuaryLinesIntersect"
outType = "LINE"

# Make lines
arcpy.Intersect_analysis(inFeatures, outFeatures, "", "", outType)

#Print end time
print "Finished "+str(datetime.now() - startTime)


Minha pergunta é: existe uma maneira de fazer a CPU funcionar a 100%? Está funcionando a 25% o tempo todo. Eu acho que o script seria executado mais rápido se o processador estivesse em 100%. Adivinhar errado?
Minha máquina é:

  • Windows Server 2012 R2 Standard
  • Processador: Intel Xeon CPU E5-2630 0 @ 2.30 GHz 2.29 GHz
  • Memória instalada: 31,6 GB
  • Tipo de sistema: Sistema operacional de 64 bits, processador baseado em x64


insira a descrição da imagem aqui

Manuel Frias
fonte
Eu sugeriria fortemente a opção de multi-threading. Isso não é trivial de configurar, mas compensará mais do que os esforços.
alok JAI
11
Que tipo de índice espacial você aplicou aos seus polígonos?
Kirk Kuykendall
11
Além disso, você tentou a mesma operação com o ArcGIS Pro? É de 64 bits e suporta multithread. Eu ficaria surpreso se for inteligente o suficiente para dividir um Intersect em vários threads, mas vale a pena tentar.
Kirk Kuykendall
A classe de recurso de polígono possui um índice espacial chamado FDO_Shape. Eu não pensei sobre isso. Devo criar outro? Isso não é suficiente?
Manuel Frias
11
Como você tem muita RAM ... você tentou copiar os polígonos em uma classe de featureclasse na memória e, em seguida, cruzou as linhas com isso? Ou, se mantendo-o em disco, você tentou compactá-lo? Supostamente a compactação melhora a E / S.
precisa saber é o seguinte

Respostas:

13

Deixe-me adivinhar: sua CPU possui 4 núcleos, portanto, 25% de CPU, é 100% de um núcleo e 3 núcleos ociosos.

Portanto, a única solução é tornar o código multiencadeado, mas essa não é uma tarefa simples.

MTilsted
fonte
4
A CPU que ele menciona utiliza 6 núcleos e 12 threads.
Kersten
5
Olá, não posso reduzir o voto, mas gostaria! Python tem uma GIL infelizmente para que você possa material não multithread em tudo (o melhor que você pode fazer é ter o GIL desbloqueado Quando um segmento blocos em um syscall)
Alec Teal
2
@AlecTeal você definitivamente pode, por exemplo, com Jython ou o multiprocessingmódulo.
rightfold 16/09/15
@elyse: "Ah, sim, você pode fazer isso totalmente em Python, se por Python você quer dizer Jython" não conta. Eu precisaria estudar o multiprocessamento. Uma importação teria o poder de reimplementar o que torna o Python Python?
Alec Teal
@AlecTeal Gera processos (que são uma maneira de fazer paralelismo). Veja a documentação do multiprocessingmódulo.
rightfold 18/09/15
13

Não tenho tanta certeza de que essa seja uma tarefa vinculada à CPU. Eu pensaria que seria uma operação vinculada a E / S, portanto, estaria procurando usar o disco mais rápido ao qual tinha acesso.

Se E: for uma unidade de rede, eliminar esse seria o primeiro passo. Se não for um disco de alto desempenho (busca <7ms), isso seria o segundo. Você pode obter algum benefício ao copiar a camada de polígono para um in_memoryespaço de trabalho, mas o benefício pode depender do tamanho da classe de recurso de polígono e se você está usando o processamento em segundo plano de 64 bits.

A otimização da taxa de transferência de E / S costuma ser a chave para o desempenho do GIS; portanto, recomendo que você preste menos atenção ao medidor de CPU e mais atenção aos medidores de rede e disco.

Vince
fonte
4

Eu tive problemas semelhantes de desempenho em relação aos scripts arcpy, o principal gargalo não é a CPU no disco rígido, se você estiver usando dados da rede que é o pior cenário, tente mover os dados para a unidade SSD e inicie o script na linha de comando não do pyscripter, o pyscripter é um pouco mais lento pode ser porque contém algumas coisas de depuração; se você não estiver satisfeito novamente, pense em paralelizar seu script, porque cada thread python ocupa um núcleo da CPU, sua CPU possui 6 núcleos, para que você possa iniciar 6 scripts simultaneamente.

geogeek
fonte
3

Como você está usando python e como sugerido acima, considere o uso de multiprocessamento se seu problema puder ser executado em paralelo.

Escrevi um pequeno artigo no site da geonet sobre a conversão de um script python em uma ferramenta de script python que poderia ser usada no modelbuilder. O documento lista o código e descreve algumas armadilhas para executá-lo como uma ferramenta de script. Este é apenas um lugar para começar a procurar:

https://geonet.esri.com/docs/DOC-3824

Hornbydd
fonte
Este parece o caminho a seguir! Seu script funciona bem, mas não sei como modificá-lo para fazê-lo funcionar com o meu script. Melhor, eu estava pensando em fazer uma interseção tabulada com polígonos e linhas. Qualquer ideia?
Manuel Frias
3

Como dito antes, você deve usar multiprocessamento ou encadeamento . Mas aqui vem a ressalva: o problema deve ser divisível! Portanto, consulte https://en.wikipedia.org/wiki/Divide_and_conquer_algorithms .

Se o seu problema é divisível, você deve proceder da seguinte maneira:

  • Crie uma fila onde você armazena os dados de entrada para os processos / encadeamento
  • Crie uma fila em que os resultados sejam armazenados
  • Crie uma função ou classe que possa ser usada como um processo / thread que resolva nosso problema

Mas, como a geogeek disse, pode não ser um problema de limitação de CPU, mas um problema de E / S. Se você tiver RAM suficiente, poderá pré-carregar todos os dados e processá-los, o que tem a vantagem de que os dados podem ser lidos de uma só vez, portanto, nem sempre interrompe o processo de cálculo.

Benjamin
fonte
3

Decidi testá-lo usando 21513 linhas e 498596 polígonos. Testei a abordagem multiprocessador (12 processadores na minha máquina) usando este script:

import arcpy,os
import multiprocessing
import time
t0 = time.time()
arcpy.env.overwriteOutput = True
nProcessors=4
folder=r'd:\scratch'

def function(inputs):
        nGroup=inputs[0]
        pGons=inputs[1]
        lines=inputs[2]
        outFeatures = '%s%s%s_%i.shp' %(folder,os.sep,'inters',nGroup)
        fids= tuple([i for i in range(nGroup,500000,nProcessors-1)])
        lyr='layer%s'%nGroup
        query='"FID" in %s' %str(fids)
        arcpy.MakeFeatureLayer_management(pGons,lyr,query)
        arcpy.Intersect_analysis([lines,lyr], outFeatures)
        return outFeatures
if __name__ == "__main__":
        inPgons='%s%s%s' %(folder,os.sep,'parcels.shp')
        inLines='%s%s%s' %(folder,os.sep,'roads.shp')
        m,bList=0,[]
        for i in range(nProcessors):
                bList.append([i,inPgons,inLines])
        pool = multiprocessing.Pool(nProcessors-1)
        listik=pool.map(function, bList)
##      apply merge here
        print listik
        print ('%i seconds' %(time.time()-t0))

Resultados, segundos:

  • disco rígido local normal - 191
  • unidade local super rápida - 220
  • unidade de rede - 252

O engraçado é que demorou apenas 87 segundos usando a ferramenta de geoprocessamento do mxd. Talvez algo de errado com minha abordagem à piscina ...

Como se pode ver, usei o FID de consulta bastante feio em (0, 4, 8,12… 500000) para tornar a tarefa divisível.

É possível que a consulta baseada no campo pré-calculado, por exemplo, CFIELD = 0, reduza bastante o tempo.

Também descobri que o tempo relatado pelas ferramentas de multiprocessamento pode variar bastante.

FelixIP
fonte
11
Sim, você está usando uma lista, que acompanha problemas de bloqueio. Experimente um multiprocessing.queue. Tente também não gravar coisas nos processos de trabalho, mas crie uma fila de saída com os dados que deseja gravar e deixe que isso seja feito por um processo de gravação.
Benjamin
3

Eu não estou familiarizado com o PyScripter, mas se for apoiado pelo CPython, você deve optar pelo multiprocessamento e não pelo multi-threading, desde que o problema em si seja divisível (como outros já o mencionaram).

O CPython possui um bloqueio global de intérpretes , que cancela todos os benefícios que vários threads podem trazer no seu caso .

Certamente, em outros contextos, os threads python são úteis, mas não nos casos em que você está vinculado à CPU.

user1514631
fonte
1

Minha pergunta é: existe uma maneira de fazer a CPU funcionar a 100%

Como sua CPU possui vários núcleos, você apenas maximizará o núcleo em que seu processo está sendo executado. Dependendo de como você configurou o seu chip Xeon, ele estará executando até 12 núcleos (6 físicos e 6 virtuais com o hyperthreading ativado). Mesmo o ArcGIS de 64 bits não é realmente capaz de tirar proveito disso - e isso pode resultar em limitações da CPU quando o seu processo de encadeamento único maximiza o núcleo em que está sendo executado. Você precisa de um aplicativo multithread para distribuir a carga pelos núcleos OU (muito mais simplesmente), você pode reduzir o número de núcleos que sua CPU está executando para aumentar a taxa de transferência.

A maneira mais fácil de interromper a limitação da CPU (e certificar-se de que realmente é limitação da CPU e não restrições de E / S de disco) é alterar as configurações de BIOS do seu Xeon e defini-las como um único núcleo maciço. O aumento de desempenho será substancial. Lembre-se de que isso também reduz consideravelmente a capacidade de multitarefa do seu PC, então é melhor se você tiver uma máquina de processo dedicada para implementá-la. É muito mais simples do que tentar multiencadear seu código - que a maioria das funções do ArcGIS Desktop (como em 10.3.1) não suporta de qualquer maneira.

kingmi
fonte
Que configuração você deve procurar para transformar sua CPU em "um único núcleo maciço"?
Alex McVittie
11
O menu exato dependerá do firmware do BIOS e do chip, mas geralmente estará em Configuração do menu do BIOS> Avançado> Configuração da CPU. Você deseja desativar o hyperthreading e depois definir o número de núcleos a serem ativados. 0 geralmente é tudo - definido como 1 se você deseja um grande núcleo. É uma boa idéia anotar as configurações antes de mudar as coisas - parece óbvio, mas fácil de ignorar, se as coisas não derem certo.
kingmi