Maximizando el uso de CPU

9

Mi guión está intersectando líneas con polígonos. Es un proceso largo ya que hay más de 3000 líneas y más de 500000 polígonos. Ejecuté desde 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)


Mi pregunta es: ¿hay alguna manera de hacer que la CPU funcione al 100%? Está funcionando al 25% todo el tiempo. Supongo que el script correría más rápido si el procesador estuviera al 100%. ¿Suposición equivocada?
Mi maquina es:

  • Windows Server 2012 R2 Standard
  • Procesador: CPU Intel Xeon E5-2630 0 @ 2.30 GHz 2.29 GHz
  • Memoria instalada: 31,6 GB
  • Tipo de sistema: sistema operativo de 64 bits, procesador basado en x64


ingrese la descripción de la imagen aquí

Manuel Frias
fuente
Sugeriría encarecidamente optar por subprocesos múltiples. No es trivial de configurar, pero compensará con creces los esfuerzos.
alok jha
1
¿Qué tipo de índice espacial has aplicado a tus polígonos?
Kirk Kuykendall
1
Además, ¿ha intentado la misma operación con ArcGIS Pro? Es de 64 bits y admite multiproceso. Me sorprendería si es lo suficientemente inteligente como para dividir un Intersect en múltiples hilos, pero vale la pena intentarlo.
Kirk Kuykendall
La clase de entidad poligonal tiene un índice espacial llamado FDO_Shape. No he pensado en esto. ¿Debo crear otro? ¿No es esto suficiente?
Manuel Frias
1
Como tienes mucha RAM ... ¿intentaste copiar los polígonos en una clase de características en memoria y luego se cruzan las líneas con eso? O si lo mantienes en el disco, ¿intentaste compactarlo? Supuestamente, la compactación mejora la E / S.
Kirk Kuykendall

Respuestas:

13

Déjame adivinar: tu CPU tiene 4 núcleos, por lo que el 25% de uso de la CPU es el 100% del uso de un núcleo y 3 núcleos inactivos.

Entonces, la única solución es hacer que el código sea multiproceso, pero esa no es una tarea simple.

MTilsted
fuente
44
La CPU que menciona utiliza 6 núcleos y 12 hilos.
Kersten
55
Hola, no puedo votar a favor, ¡pero me gustaría! Desafortunadamente, Python tiene un GIL, por lo que no puede hacer múltiples hilos (lo mejor que puede hacer es desbloquear el GIL cuando un hilo se bloquea en una llamada al sistema)
Alec Teal
2
@AlecTeal definitivamente puedes, por ejemplo con Jython o el multiprocessingmódulo.
derecha el
@elyse dice "Oh, sí, puedes hacer eso totalmente en Python, si por Python te refieres a Jython" no cuenta. Tendría que analizar el multiprocesamiento, ¿una importación tendría el poder de reimplementar lo que hace Python Python?
Alec Teal
@AlecTeal Genera procesos (que son una forma de hacer paralelismo). Consulte la documentación del multiprocessingmódulo.
derecha el
13

No estoy tan seguro de que esta sea una tarea vinculada a la CPU. Creo que sería una operación vinculada a E / S, por lo que buscaría usar el disco más rápido al que tuviera acceso.

Si E: es una unidad de red, eliminar ese sería el primer paso. Si no es un disco de alto rendimiento (<7 ms de búsqueda), entonces sería el segundo. Puede obtener algún beneficio al copiar la capa de polígono en un in_memoryespacio de trabajo, pero el beneficio puede depender del tamaño de la clase de entidad de polígono y de si está utilizando el procesamiento de fondo de 64 bits.

La optimización del rendimiento de E / S suele ser clave para el rendimiento de los SIG, por lo que le recomiendo que preste menos atención al medidor de la CPU y más a la red y a los medidores de disco.

Vince
fuente
4

Tuve problemas similares de rendimiento con respecto a las secuencias de comandos arcpy, el principal cuello de botella no es la CPU sino el disco duro, si está utilizando datos de la red que es el peor escenario, intente mover sus datos a la unidad SSD, luego inicie su secuencia de comandos desde la línea de comandos no de pyscripter, pyscripter es un poco más lento puede ser porque contiene algunas cosas de depuración, si no está satisfecho de nuevo, piense en poner en paralelo su script, porque cada hilo de Python toma un núcleo de CPU, su CPU tiene 6 núcleos, por lo que puede iniciar 6 guiones simultáneamente.

geogeek
fuente
3

Como está usando python y como se sugirió anteriormente, considere usar multiprocesamiento si su problema se puede ejecutar en paralelo.

Escribí un pequeño artículo en el sitio web de geonet sobre cómo convertir una secuencia de comandos de Python en una herramienta de secuencia de comandos de Python que podría usarse dentro de modelbuilder. El documento enumera el código y describe algunas dificultades para ejecutarlo como una herramienta de secuencia de comandos. Este es solo un lugar para comenzar a buscar:

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

Hornbydd
fuente
¡Este parece ser el camino a seguir! Su script funciona bien pero no sé cómo modificarlo para que funcione con mi script. Mejor, estaba pensando en hacer una intersección tabulada con polígonos y líneas. ¿Alguna idea?
Manuel Frias
3

Como se dijo antes, debe usar multiprocesamiento o subprocesamiento . Pero aquí viene la advertencia: ¡El problema debe ser divisible! Eche un vistazo a https://en.wikipedia.org/wiki/Divide_and_conquer_algorithms .

Si su problema es divisible, procedería como:

  • Cree una cola donde almacene los datos de entrada para los procesos / hilo
  • Crea una cola donde se almacenan los resultados
  • Cree una función o clase que pueda usarse como un proceso / hilo que resuelva nuestro problema

Pero como ha dicho Geogeek, podría no ser un problema de limitación de CPU, sino un problema de IO. Si tiene suficiente RAM, puede precargar todos los datos y luego procesarlos, lo que tiene la ventaja de que los datos se pueden leer de una vez, por lo que no siempre interrumpe el proceso de cálculo.

Benjamín
fuente
3

Decidí probarlo usando 21513 líneas y 498596 polígonos. Probé el enfoque multiprocesador (12 procesadores en mi 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 duro local normal - 191
  • unidad local superrápida - 220
  • unidad de red - 252

Lo divertido fue que solo tardó 87 segundos usando la herramienta de geoprocesamiento de mxd. Tal vez algo mal con mi enfoque de la piscina ...

Como se puede ver, he usado un FID de consulta bastante feo en (0, 4, 8,12… 500000) para hacer que la tarea sea divisible.

Es posible que la consulta basada en un campo precalculado, por ejemplo, CFIELD = 0 reduzca el tiempo en gran medida.

También descubrí que el tiempo reportado por las herramientas de multiprocesamiento puede variar mucho.

FelixIP
fuente
1
Sí, estás usando una lista, que viene junto con problemas de bloqueo. Prueba un multiprocessing.queue. También trate de no escribir cosas en los procesos de trabajo, pero cree una cola de salida con los datos que desea escribir y deje que esto sea realizado por un proceso de escritura.
Benjamin
3

No estoy familiarizado con PyScripter, pero si está respaldado por CPython, entonces debería optar por el multiprocesamiento y no por el subprocesamiento múltiple siempre que el problema en sí sea divisible (como otros ya lo mencionaron).

CPython tiene un bloqueo global de intérprete , que cancela cualquier beneficio que múltiples hilos puedan aportar en su caso .

Por supuesto, en otros contextos, los subprocesos de Python son útiles, pero no en los casos en que está vinculado a la CPU.

usuario1514631
fuente
1

Mi pregunta es: ¿hay alguna manera de hacer que la CPU funcione al 100%?

Como su CPU tiene múltiples núcleos, solo maximizará el núcleo en el que se está ejecutando su proceso. Dependiendo de cómo haya configurado su chip Xeon, ejecutará hasta 12 núcleos (6 físicos y 6 virtuales con hyperthreading activado). Incluso ArcGIS de 64 bits realmente no puede aprovechar esto, y eso puede dar lugar a limitaciones de la CPU cuando su proceso de subproceso único maximiza el núcleo en el que se ejecuta. Necesita una aplicación multiproceso para distribuir la carga entre los núcleos O (mucho más simple) puede reducir la cantidad de núcleos que su CPU está ejecutando para aumentar el rendimiento.

La forma más fácil de detener la limitación de la CPU (y asegurarse de que realmente sea la limitación de la CPU y no las restricciones de E / S del disco) es cambiar la configuración del BIOS para su Xeon y configurarlo en un solo núcleo masivo. El aumento del rendimiento será sustancial. Solo recuerde que esto también intercambia considerablemente la capacidad de multitarea de su PC, por lo que es mejor si tiene una máquina de proceso dedicada para implementar esto. Es mucho más simple que intentar multiprocesar su código, que la mayoría de las funciones de ArcGIS Desktop (como en 10.3.1) no son compatibles de todos modos.

kingmi
fuente
¿Qué configuración debe buscar para convertir su CPU en "un solo núcleo masivo"?
Alex McVittie
1
El menú exacto dependerá de su BIOS y firmware de chip, pero generalmente estará en Configuración del menú del BIOS> Avanzado> Configuración de la CPU. Deberá desactivar el hiperprocesamiento y luego establecer el número de núcleos para activar. 0 es generalmente todo: se establece en 1 si desea un núcleo grande. Es una buena idea tomar nota de la configuración antes de cambiar las cosas; parece obvio pero fácil de pasar por alto si las cosas no funcionan.
Kingmi