与以前的版本相比,如何提高数据访问游标的性能?


18

数据访问模块是ArcGIS 10.1版引入的。ESRI对数据访问模块的描述如下():

数据访问模块arcpy.da是用于处理数据的Python模块。它允许控制编辑会话,编辑操作,改进的光标支持(包括更快的性能),用于在NumPy数组之间来回转换表和要素类的功能,以及对版本控制,副本,域和子类型工作流的支持。

但是,关于为何为什么游标性能比上一代游标如此提高的信息很少。

上图显示了在新da方法UpdateCursor与旧方法UpdateCursor 上进行基准测试的结果。本质上,脚本执行以下工作流程:

  1. 创建随机点(10、100、1000、10000、100000)
  2. 从正态分布中随机采样,然后使用光标将值添加到随机点属性表中的新列
  3. 针对新的和旧的UpdateCursor方法,对每个随机点方案运行5次迭代,并将平均值写入列表
  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()

Answers:


25

arcpy.da这里的开发商之一。我们之所以能够获得性能,是因为性能是我们最关心的问题:旧游标的主要困扰在于它们运行缓慢,而不是缺少任何特定功能。该代码使用自8.x以来ArcGIS中可用的底层ArcObjects(例如,搜索光标的CPython实现在其实现中看起来很像这样的代码示例,但您知道,是使用C ++而不是C#)。

因此,我们要做的主要两件事是:

  1. 消除抽象层: Python游标的初始实现基于旧的基于Dispatch / COM的GPDispatch对象,该对象使人们能够以任何可以使用COM Dispatch对象的语言使用相同的API。这意味着您没有针对任何单个环境进行特别优化的API,但是这也意味着,例如,在运行时,COM对象有很多抽象层可以通告和解析方法。如果您还记得ArcGIS 9.3之前的版本,则可以使用相同的笨拙界面编写多种语言(甚至包括Perl和Ruby)来编写地理处理脚本。对象需要做的额外文书工作IDispatch 东西增加了很多复杂性,降低了函数调用的速度。
  2. 请使用Python的成语和数据结构紧密集成,具体的Python C ++库:的想法一个Row对象,并真是个奇怪的while cursor.Next():舞蹈只是简单的低效Python编写的。从列表中获取项目是一个非常快的操作,并且简化为仅几个CPython函数调用(基本上是一个__getitem__调用,在列表上进行了大量优化)。这样row.getValue("column")的比较是更重量级的:它确实__getattr__来获取方法(在它需要创建一个新的绑定方法的对象),然后调用与给定的参数是方法(__call__)。在每一部分arcpy.da实现非常与CPython的API紧密结合 使用本地Python数据结构(以及numpy集成,还可以提高速度和内存效率)使用大量手动调整的C ++使其变得更快。

您还会注意到,在几乎所有基准测试中(例如请参见这些幻灯片),. Net和C ++中的arcobject的运行速度仍arcpy.da是大多数任务中的两倍。使用Python代码arcpy.da的速度更快,但仍不比编译的底层语言快。

TL; DRda速度更快,因为它da是在纯净,纯净的Arcobjects / C ++ / CPython中实现的,而Arcobjects / C ++ / CPython是专门为生成快速Python代码而设计的。


4

绩效相关

  • 默认情况下,Cursor仅迭代设置的字段列表(而不是整个数据库)

其他与性能没有直接关系,但有一些不错的增强功能:

  • 使用令牌(例如SHAPE @ LENGTH,SHAPE @ XY)访问要素几何的能力
  • 能够遍历数据库(使用arcpy.da.Walk方法)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.