Як ефективність курсору доступу до даних настільки підвищена порівняно з попередніми версіями?


18

Модуль доступу до даних був представлений з ArcGIS версії 10.1. ESRI описує модуль доступу до даних наступним чином ( джерело ):

Модуль доступу до даних, arcpy.da, є модулем Python для роботи з даними. Це дозволяє контролювати сеанс редагування, операцію редагування, покращену підтримку курсору (включаючи більш високу продуктивність), функції для перетворення таблиць і класів функцій в масиви NumPy і з них, а також підтримку робочих процесів версій, реплік, доменів і підтипів.

Однак є дуже мало інформації щодо того, чому продуктивність курсора настільки поліпшена порівняно з попереднім поколінням курсорів.

На малюнку, що додається, показані результати тесту на орієнтир нового daметоду UpdateCursor порівняно зі старим методом UpdateCursor. По суті, сценарій виконує такий робочий процес:

  1. Створіть випадкові точки (10, 100, 1000, 10000, 100000)
  2. Випадково вибірки з звичайного розподілу і додайте значення до нового стовпця в таблиці атрибутів випадкових точок з курсором
  3. Виконайте 5 ітерацій кожного сценарію випадкових точок як для нових, так і для старих методів UpdateCursor та запишіть середнє значення у списки
  4. Позначте результати

Що відбувається за кадром з daкурсором оновлення, щоб покращити ефективність курсора до ступеня, показаної на рисунку?


введіть тут опис зображення


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

Відповіді:


25

Один із розробників arcpy.daтут. Ми отримали виставу там, де вона є, тому що продуктивність була нашою основною турботою : головна боротьба зі старими курсорами полягала в тому, що вони були повільними, а не тим, що їм не вистачало певної функціональності. Код використовує ті самі основні ArcObjects, які доступні в ArcGIS з 8.x (реалізація пошукового курсора CPython, схоже, у своїй реалізації схожа на зразки коду, подібні цьому, за винятком C ++ замість C #).

Основні дві речі, які ми зробили для досягнення прискорення, це:

  1. Усуньте шари абстракції: початкова реалізація курсору Python базувалася на старому об’єкті GPDispatch на основі Dispatch / COM , що дозволило використовувати той самий API будь-якою мовою, яка могла б споживати об’єкти COM Dispatch . Це означає, що у вас був API, який не був особливо оптимізований для будь-якого окремого середовища, але це також означало, що для об'єктів COM, наприклад , існує багато шарів абстракції для рекламування та вирішення методів. Якщо ви пам’ятаєте раніше ArcGIS 9.3, можна було писати сценарії геообробки, використовуючи той самий незграбний інтерфейс багатьох мов, навіть Perl і Ruby . Додатковий папір, який повинен зробити об'єкт для обробкиIDispatch речі додають багато складності та уповільнення функціонування дзвінків.
  2. Зробіть тісно інтегровану, Python конкретні C ++ бібліотеки з використанням віщих ідіом і структур даних: ідея з Rowоб'єктом і дійсно дивного while cursor.Next():танець була просто неефективні в Python. Вилучення елемента зі списку - це дуже швидка операція, яка спрощує лише кілька викликів функції CPython (в основному __getitem__дзвінок, сильно оптимізований у списках). Робота row.getValue("column")в порівнянні більш важка: вона робить __getattr__метод для отримання (за допомогою якого потрібно створити новий об'єкт методу), а потім викликає цей метод із заданими аргументами ( __call__). Кожна частина arcpy.daреалізації дуже тісно інтегрована з API CPython з великою кількістю налагоджених C ++, щоб зробити його швидким, використовуючи нативні структури даних Python (і інтеграцію numpy теж для більшої швидкості та ефективності пам'яті).

Ви також помітите, що майже в будь-якому еталоні ( див., Наприклад , ці слайди ) аркобекти в .Net та C ++ все ще вдвічі швидші, ніж arcpy.daу більшості завдань. Використання коду Python arcpy.da- це швидше, але все ж не швидше, ніж компільована мова нижчого рівня.

TL; DR : daшвидше, тому що daреалізується в прямолінійному, непорушеному Arcobjects / C ++ / CPython, який був спеціально розроблений для швидкого отримання Python-коду.


4

Виконання продуктивності

  • Курсор ітератує лише встановлений список полів за замовчуванням (не всю базу даних)

Інші, не пов'язані безпосередньо з продуктивністю, але приємні покращення:

  • Можливість використання лексем (наприклад, SHAPE @ LENGTH, SHAPE @ XY) для доступу до геометрії функцій
  • Можливість ходити по базах даних (використовуючи метод arcpy.da.Walk )
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.