Veri erişim imleci performansı önceki sürümlere göre nasıl bu kadar gelişmiş?


18

Veri erişim modülü ArcGIS sürüm 10.1 ile tanıtıldı. ESRI, veri erişim modülünü şu şekilde açıklar ( kaynak ):

Veri erişim modülü, arcpy.da, verilerle çalışmak için bir Python modülüdür. Düzenleme oturumunun, düzenleme işleminin, gelişmiş imleç desteğinin (daha hızlı performans dahil), tabloları ve özellik sınıflarını NumPy dizilerine ve NumPy dizilerinden dönüştürmeye yönelik işlevlere ve sürüm oluşturma, çoğaltma, etki alanları ve alt tür iş akışları desteğine izin verir.

Ancak, imleç performansının önceki nesil imleçlere göre neden bu kadar geliştiğine dair çok az bilgi var.

Ekteki şekil, yeni daUpdateCursor yöntemiyle eski UpdateCursor yöntemine ilişkin bir karşılaştırma testinin sonuçlarını gösterir . Temel olarak, komut dosyası aşağıdaki iş akışını gerçekleştirir:

  1. Rastgele noktalar oluşturun (10, 100, 1000, 10000, 100000)
  2. Normal bir dağılımdan rastgele örnek alın ve imleçle rastgele noktalar özellik tablosundaki yeni bir sütuna değer ekleyin
  3. Hem yeni hem de eski UpdateCursor yöntemleri için her rastgele nokta senaryosunun 5 yinelemesini çalıştırın ve ortalama değeri listelere yazın
  4. Sonuçları çizin

daİmleç performansını şekilde gösterilen dereceye yükseltmek için güncelleme imleci ile perde arkasında neler oluyor ?


resim açıklamasını buraya girin


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

Yanıtlar:


25

arcpy.daBuradaki geliştiricilerden biri . Performansı, performansın birincil kaygımız olduğu için aldık : eski imleçlerle ilgili asıl sıkıntı, belirli bir işlevsellikten yoksun olmaları değil, yavaş olmalarıydı. Kod, 8.x'ten bu yana ArcGIS'te bulunan aynı ArcObjects'i kullanıyor (örneğin, arama imlecinin CPython uygulaması, örneğin, C # yerine C ++ hariç, uygulamada bunun gibi kod örneklerine çok benziyor ).

Hızlandırmayı elde etmek için yaptığımız başlıca iki şey:

  1. Soyutlama katmanlarını ortadan kaldırın: Python imlecinin ilk uygulaması, eski Dispatch / COM tabanlı GPDispatch nesnesine dayanıyordu , bu da COM Dispatch nesnelerini tüketebilecek herhangi bir dilde aynı API'yi kullanmasını sağladı . Bu, herhangi bir tek ortam için özellikle iyi optimize edilmemiş bir API'ye sahip olduğunuz anlamına gelir, ancak aynı zamanda COM nesnelerinin çalışma zamanında yöntemleri tanıtması ve çözmesi için çok sayıda soyutlama katmanı olduğu anlamına gelir . ArcGIS 9.3'ten önce hatırlarsanız, Perl ve Ruby de dahil olmak üzere aynı karmaşık arayüzü kullanarak coğrafi işlem komut dosyaları yazmak mümkün oldu . Bir nesneninIDispatch stuff, işlev çağrılarına çok fazla karmaşıklık ve yavaşlama ekler.
  2. Pythonic deyimleri ve veri yapılarını kullanarak sıkı bir şekilde entegre, Python'a özgü bir C ++ kütüphanesi oluşturun: bir Rownesne fikri ve gerçekten garip while cursor.Next():dans Python'da sadece verimsizdi. Listeden bir öğe getirmek çok hızlı bir işlemdir ve sadece birkaç CPython işlev çağrısına kadar basitleştirir (temel olarak bir __getitem__çağrı, listelerde yoğun bir şekilde optimize edilmiştir). Doing row.getValue("column")kıyasla daha ağır: bir does __getattr__(yeni bir bağımlı yöntem nesnesi oluşturmak gerekiyor hangi) yöntemini getirmesi, ardından (verilen argümanlar ile bu yöntemi çağırın __call__). Her bölüm arcpy.dauygulanması olduğunu çok yakından CPython API ile entegre yerel Python veri yapılarını (ve daha da fazla hız ve bellek verimliliği için de numpy entegrasyonu) kullanarak, hızlı hale getirmek için birçok elle ayarlanmış C ++ ile.

Ayrıca, neredeyse tüm karşılaştırmalı değerlendirmelerde ( örneğin bu slaytlara bakın ), .Net ve C ++ 'daki arcobjects hala arcpy.daçoğu görevde iki kat daha hızlıdır . Python kodunu kullanmak arcpy.dadaha hızlıdır, ancak yine de derlenmiş, daha düşük seviyeli bir dilden daha hızlı değildir.

TL; DR : dadaha hızlıdır, çünkü dahızlı Python koduyla sonuçlanmak üzere özel olarak tasarlanmış düz, katkısız Arcobjects / C ++ / CPython'da uygulanmıştır.


4

Performansla ilgili

  • İmleç, varsayılan olarak yalnızca ayarlanan alan listesini tekrarlar (tüm veritabanını değil)

Doğrudan performansla ilgili olmayan, ancak güzel geliştirmeler:

  • Özellik geometrisine erişmek için jeton kullanabilme (örn. SHAPE @ LENGTH, SHAPE @ XY)
  • Veritabanlarında yürüyebilme ( arcpy.da.Walk yöntemini kullanarak )
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.