19 votos

¿Cómo es que el rendimiento del cursor de acceso a los datos ha mejorado tanto en comparación con las versiones anteriores?

El módulo de acceso a datos se introdujo con la versión 10.1 de ArcGIS. ESRI describe el módulo de acceso a datos de la siguiente manera ( fuente ):

El módulo de acceso a datos, arcpy.da, es un módulo de Python para trabajar con datos. Permite el control de la sesión de edición, la operación de edición, el soporte mejorado del soporte del cursor (incluyendo un rendimiento más rápido), funciones para convertir tablas y clases de características a y desde matrices NumPy, y soporte para flujos de trabajo de versiones, réplicas, dominios y subtipos.

Sin embargo, hay muy poca información sobre la razón por la que el rendimiento del cursor ha mejorado tanto con respecto a la generación anterior de cursores.

La figura adjunta muestra los resultados de una prueba de referencia en el nuevo da método UpdateCursor frente al antiguo método UpdateCursor. Esencialmente, el script realiza el siguiente flujo de trabajo:

  1. Crear puntos aleatorios (10, 100, 1000, 10000, 100000)
  2. Tomar una muestra aleatoria de una distribución normal y añadir valor a un nuevo columna en la tabla de atributos de puntos aleatorios con un cursor
  3. Ejecuta 5 iteraciones de cada escenario de puntos aleatorios para los métodos UpdateCursor nuevo y antiguo y escribe el valor medio en las listas
  4. Trazar los resultados

¿Qué está pasando entre bastidores con el da actualizar el cursor para mejorar el rendimiento del cursor en el grado mostrado en la figura?


enter image description here


import arcpy, os, numpy, time
arcpy.env.overwriteOutput = True

outws = r'C:\temp'
fc = os.path.join(outws, 'randomPoints.shp')

iterations = [10, 100, 1000, 10000, 100000]
old = []
new = []

meanOld = []
meanNew = []

for x in iterations:
    arcpy.CreateRandomPoints_management(outws, 'randomPoints', '', '', x)
    arcpy.AddField_management(fc, 'randFloat', 'FLOAT')

    for y in range(5):

        # Old method ArcGIS 10.0 and earlier
        start = time.clock()

        rows = arcpy.UpdateCursor(fc)

        for row in rows:
            # generate random float from normal distribution
            s = float(numpy.random.normal(100, 10, 1))
            row.randFloat = s
            rows.updateRow(row)

        del row, rows

        end = time.clock()
        total = end - start
        old.append(total)

        del start, end, total

        # New method 10.1 and later
        start = time.clock()

        with arcpy.da.UpdateCursor(fc, ['randFloat']) as cursor:
            for row in cursor:
                # generate random float from normal distribution
                s = float(numpy.random.normal(100, 10, 1))
                row[0] = s
                cursor.updateRow(row)

        end = time.clock()
        total = end - start
        new.append(total)
        del start, end, total
    meanOld.append(round(numpy.mean(old),4))
    meanNew.append(round(numpy.mean(new),4))

#######################
# plot the results

import matplotlib.pyplot as plt
plt.plot(iterations, meanNew, label = 'New (da)')
plt.plot(iterations, meanOld, label = 'Old')
plt.title('arcpy.da.UpdateCursor -vs- arcpy.UpdateCursor')
plt.xlabel('Random Points')
plt.ylabel('Time (minutes)')
plt.legend(loc = 2)
plt.show()

26voto

Paul Puntos 555

Uno de los desarrolladores de arcpy.da aquí. Tenemos el rendimiento donde está porque el rendimiento era nuestra principal preocupación El código de la aplicación: la principal queja con los antiguos cursores era que eran lentos, no que carecieran de ninguna funcionalidad en particular. El código utiliza los mismos ArcObjects subyacentes disponibles en ArcGIS desde 8.x (la implementación CPython del cursor de búsqueda, por ejemplo, se parece mucho a muestras de código como esta en su implementación excepto, ya sabes, en C++ en lugar de C#).

Las dos cosas principales que hemos hecho para conseguir la aceleración son las siguientes:

  1. Eliminar las capas de abstracción: la implementación inicial del cursor de Python se basaba en el antiguo Objeto GPDispatch basado en Dispatch/COM que permitía utilizar la misma API en cualquier lenguaje que pueda consumir Objetos de despacho COM . Esto significa que se tenía una API que no estaba particularmente bien optimizada para un solo entorno, pero también significaba que había un lote de capas de abstracción para que los objetos COM anuncien y resuelvan métodos en tiempo de ejecución, por ejemplo. Si recuerda que antes de ArcGIS 9.3, era posible escribir scripts de geoprocesamiento utilizando esa misma interfaz torpe muchos lenguajes, incluso Perl y Ruby . El papeleo adicional que necesita un objeto para manejar el IDispatch añade mucha complejidad y ralentización a las llamadas de función.
  2. Hacer una biblioteca C++ específica de Python, estrechamente integrada, utilizando modismos y estructuras de datos pitónicos: la idea de a Row objeto y lo realmente extraño while cursor.Next(): danza eran simplemente ineficientes en Python. Obtener un elemento de una lista es una operación muy rápida, y se reduce a un par de llamadas a funciones de CPython (básicamente un __getitem__ llamada, muy optimizada en las listas). Haciendo row.getValue("column") en comparación es más pesado: hace un __getattr__ para obtener el método (sobre el que necesita crear un nuevo objeto de método vinculado), y luego llamar a ese método con los argumentos dados ( __call__ ). Cada parte del arcpy.da la implementación es muy estrechamente integrado con la API de CPython con un montón de C++ ajustado a mano para que sea rápido, utilizando estructuras de datos nativas de Python (y la integración de numpy, también, para obtener aún más velocidad y eficiencia de memoria).

También observará que en casi cualquier punto de referencia ( ver estas diapositivas como ejemplo ), los arcobjects en .Net y C++ siguen siendo más del doble de rápidos que arcpy.da en la mayoría de las tareas. Código Python que utiliza arcpy.da es más rápido, pero todavía no es más rápido que un lenguaje compilado de bajo nivel.

TL;DR : da es más rápido porque da está implementado en Arcobjects/C++/CPython puro y duro, diseñado específicamente para obtener un código Python rápido.

4voto

Hameno Puntos 129

Relacionados con el rendimiento

  • El cursor sólo itera a través de una lista de campos por defecto (no toda la base de datos)

Otros que no están directamente relacionados con el rendimiento, pero que son buenas mejoras:

  • Posibilidad de utilizar tokens (por ejemplo, SHAPE@LENGTH, SHAPE@XY) para acceder a la geometría de las características
  • Capacidad para recorrer las bases de datos (utilizando arcpy.da.Walk método)

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X