Bagaimana kinerja kursor akses data begitu ditingkatkan dibandingkan dengan versi sebelumnya?

18

Modul akses data diperkenalkan dengan ArcGIS versi 10.1. ESRI menjelaskan modul akses data sebagai berikut ( sumber ):

Modul akses data, arcpy.da, adalah modul Python untuk bekerja dengan data. Ini memungkinkan kontrol sesi edit, operasi edit, dukungan kursor yang ditingkatkan (termasuk kinerja yang lebih cepat), fungsi untuk mengkonversi tabel dan kelas fitur ke dan dari array NumPy, dan dukungan untuk versi, replika, domain, dan alur kerja subtipe.

Namun, ada sangat sedikit informasi mengenai mengapa kinerja kursor sangat ditingkatkan dari generasi kursor sebelumnya.

Gambar terlampir menunjukkan hasil uji patokan pada dametode baru UpdateCursor versus metode UpdateCursor lama. Pada dasarnya, skrip melakukan alur kerja berikut:

  1. Buat poin acak (10, 100, 1000, 10000, 100000)
  2. Sampel secara acak dari distribusi normal dan tambahkan nilai ke kolom baru dalam tabel atribut poin acak dengan kursor
  3. Jalankan 5 iterasi dari setiap skenario titik acak untuk metode UpdateCursor baru dan lama dan tulis nilai rata-rata ke daftar
  4. Plot hasilnya

Apa yang terjadi di balik layar dengan dakursor pembaruan untuk meningkatkan kinerja kursor ke tingkat yang ditunjukkan pada gambar?


masukkan deskripsi gambar di sini


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

Jawaban:

25

Salah satu pengembang di arcpy.dasini. Kami mendapatkan kinerja di mana itu karena kinerja adalah perhatian utama kami : keluhan utama dengan kursor lama adalah bahwa mereka lambat, bukan karena mereka tidak memiliki fungsi tertentu. Kode menggunakan ArcObjects mendasar yang sama yang tersedia di ArcGIS sejak 8.x (implementasi CPython dari kursor pencarian, misalnya, sangat mirip dengan contoh kode seperti ini dalam implementasinya kecuali, Anda tahu, di C ++ bukannya C #).

Jadi, dua hal utama yang kami lakukan untuk mendapatkan speedup adalah:

  1. Hilangkan lapisan abstraksi: implementasi awal kursor Python didasarkan pada objek GPDispatch berbasis Dispatch / COM , yang memungkinkan seseorang untuk menggunakan API yang sama dalam bahasa apa pun yang dapat mengkonsumsi objek Dispatch COM . Ini berarti bahwa Anda memiliki API yang tidak dioptimalkan dengan baik untuk lingkungan tunggal apa pun, tetapi itu juga berarti bahwa ada banyak lapisan abstraksi untuk objek COM untuk beriklan dan menyelesaikan metode saat runtime, misalnya. Jika Anda ingat sebelum ArcGIS 9.3, dimungkinkan untuk menulis skrip geoprocessing menggunakan antarmuka canggung yang sama banyak bahasa, bahkan Perl dan Ruby . Dokumen tambahan yang perlu dilakukan objek untuk menanganiIDispatch hal-hal menambah banyak kompleksitas dan perlambatan untuk panggilan fungsi.
  2. Membuat terintegrasi, Python spesifik C ++ library menggunakan Pythonic idiom dan struktur data: ide sebuah Rowobjek dan benar-benar aneh while cursor.Next():tari sekadar tidak efisien dengan Python. Mengambil item dari daftar adalah operasi yang sangat cepat, dan menyederhanakan ke beberapa panggilan fungsi CPython (pada dasarnya __getitem__panggilan, sangat dioptimalkan pada daftar). Melakukan row.getValue("column")dengan perbandingan lebih berat: ia melakukan __getattr__untuk mengambil metode (yang dibutuhkan untuk membuat objek metode terikat baru), kemudian memanggil metode itu dengan argumen yang diberikan ( __call__). Setiap bagian dari arcpy.daimplementasi sangat terintegrasi dengan API CPython dengan banyak C ++ yang disetel dengan tangan untuk membuatnya cepat, menggunakan struktur data Python asli (dan integrasi numpy, untuk kecepatan dan efisiensi memori yang lebih tinggi).

Anda juga akan melihat bahwa di hampir semua patokan ( lihat slide ini misalnya ), objek busur di .Net dan C ++ masih lebih dari dua kali lebih cepat dari arcpy.dapada sebagian besar tugas. Penggunaan kode python arcpy.dalebih cepat, tetapi masih tidak lebih cepat dari bahasa tingkat rendah yang dikompilasi.

TL; DR : dalebih cepat karena dadiimplementasikan dalam Arcobjects / C ++ / CPython langsung yang lurus, yang dirancang khusus untuk menghasilkan kode Python yang cepat.

Jason Scheirer
sumber
4

Terkait kinerja

  • Kursor hanya beralih melalui daftar set bidang secara default (bukan seluruh database)

Lainnya tidak terkait langsung dengan kinerja, tetapi perangkat tambahan yang bagus:

  • Kemampuan untuk menggunakan token (mis. SHAPE @ LENGTH, SHAPE @ XY) untuk mengakses geometri fitur
  • Kemampuan untuk berjalan melalui basis data (menggunakan metode arcpy.da.Walk )
artwork21
sumber