In che modo le prestazioni del cursore di accesso ai dati sono così migliorate rispetto alle versioni precedenti?


18

Il modulo di accesso ai dati è stato introdotto con ArcGIS versione 10.1. ESRI descrive il modulo di accesso ai dati come segue ( fonte ):

Il modulo di accesso ai dati, arcpy.da, è un modulo Python per lavorare con i dati. Consente il controllo della sessione di modifica, l'operazione di modifica, il supporto del cursore migliorato (comprese prestazioni più veloci), le funzioni per la conversione di tabelle e classi di caratteristiche da e verso gli array NumPy e il supporto per flussi di lavoro di versioning, repliche, domini e sottotipi.

Tuttavia, ci sono pochissime informazioni sul perché le prestazioni del cursore sono così migliorate rispetto alla generazione precedente di cursori.

La figura allegata mostra i risultati di un test di riferimento sul nuovo dametodo UpdateCursor rispetto al vecchio metodo UpdateCursor. In sostanza, lo script esegue il flusso di lavoro seguente:

  1. Crea punti casuali (10, 100, 1000, 10000, 100000)
  2. Campionare casualmente da una distribuzione normale e aggiungere valore a una nuova colonna nella tabella degli attributi dei punti casuali con un cursore
  3. Esegui 5 iterazioni di ogni scenario casuale per i metodi UpdateCursor nuovi e vecchi e scrivi il valore medio negli elenchi
  4. Traccia i risultati

Cosa sta succedendo dietro le quinte con il dacursore di aggiornamento per migliorare le prestazioni del cursore nella misura mostrata nella figura?


inserisci qui la descrizione dell'immagine


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()

Risposte:


25

Uno degli sviluppatori di arcpy.daqui. Abbiamo ottenuto le prestazioni dov'è perché le prestazioni erano la nostra principale preoccupazione : la principale lamentela con i vecchi cursori era che erano lenti, non che mancassero di alcuna funzionalità particolare. Il codice utilizza gli stessi ArcObjects sottostanti disponibili in ArcGIS da 8.x (l'implementazione CPython del cursore di ricerca, ad esempio, assomiglia molto a esempi di codice come questo nella sua implementazione tranne, sai, in C ++ invece che in C #).

Le due cose principali che abbiamo fatto per ottenere l'accelerazione sono quindi:

  1. Elimina i livelli di astrazione: l'implementazione iniziale del cursore Python si basava sul vecchio oggetto GPDispatch basato su Dispatch / COM , che consentiva di utilizzare la stessa API in qualsiasi linguaggio che potesse consumare oggetti COM Dispatch . Ciò significa che avevi un'API che non era particolarmente ottimizzata per ogni singolo ambiente, ma significava anche che c'erano molti livelli di astrazione per gli oggetti COM per pubblicizzare e risolvere i metodi in fase di esecuzione, ad esempio. Se ricordi prima di ArcGIS 9.3, era possibile scrivere script di geoprocessing usando la stessa interfaccia goffa in molte lingue, anche Perl e Ruby . Le scartoffie extra che un oggetto deve fare per gestireIDispatch roba aggiunge molta complessità e rallentamento alle chiamate di funzione.
  2. Crea una libreria C ++ specifica per Python strettamente integrata usando idiomi e strutture di dati Pythonic: l'idea di un Rowoggetto e la while cursor.Next():danza davvero strana erano semplicemente inefficienti in Python. Il recupero di un elemento da un elenco è un'operazione molto rapida e semplifica fino a un paio di chiamate di funzione CPython (fondamentalmente una __getitem__chiamata, fortemente ottimizzata sugli elenchi). Fare un row.getValue("column")confronto è più pesante: fa un __getattr__per recuperare il metodo (su cui deve creare un nuovo oggetto metodo associato), quindi chiama quel metodo con gli argomenti forniti ( __call__). Ogni parte della arcpy.daattuazione è molto strettamente integrato con l'API CPython con un sacco di C ++ sintonizzato a mano per renderlo veloce, usando le strutture di dati nativi di Python (e anche l'integrazione numpy, per ancora più velocità ed efficienza di memoria).

Noterai anche che in quasi tutti i benchmark ( vedi queste diapositive per esempio ), gli oggetti arco in .Net e C ++ sono ancora due volte più veloci rispetto arcpy.daalla maggior parte delle attività. L'uso del codice Python arcpy.daè più veloce, ma comunque non più veloce di un linguaggio compilato di livello inferiore.

TL; DR : daè più veloce perché daè implementato in Arcobjects / C ++ / CPython semplice e intuitivo, che è stato specificamente progettato per produrre codice Python veloce.


4

Relativo alle prestazioni

  • Il cursore scorre solo attraverso l'elenco predefinito di campi per impostazione predefinita (non l'intero database)

Altri non direttamente correlati alle prestazioni, ma bei miglioramenti:

  • Possibilità di utilizzare i token (ad esempio SHAPE @ LENGTH, SHAPE @ XY) per accedere alla geometria della funzione
  • Capacità di camminare attraverso i database (usando il metodo arcpy.da.Walk )
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.