ประสิทธิภาพของเคอร์เซอร์การเข้าถึงข้อมูลมีการปรับปรุงอย่างไรเมื่อเทียบกับรุ่นก่อนหน้า


18

โมดูลการเข้าถึงข้อมูลถูกนำมาใช้กับ ArcGIS รุ่น 10.1 ESRI อธิบายถึง data access module ดังต่อไปนี้ ( แหล่งที่มา ):

data access module, arcpy.da เป็นโมดูล Python สำหรับการทำงานกับข้อมูล จะช่วยให้การควบคุมของเซสชั่นการแก้ไข, การดำเนินการแก้ไข, การสนับสนุนเคอร์เซอร์ที่ดีขึ้น (รวมถึงประสิทธิภาพที่เร็วขึ้น), ฟังก์ชั่นสำหรับการแปลงตารางและชั้นเรียนคุณลักษณะไปยังและจากอาร์เรย์ NumPy และการสนับสนุนสำหรับรุ่น

อย่างไรก็ตามมีข้อมูลน้อยมากเกี่ยวกับสาเหตุที่ประสิทธิภาพเคอร์เซอร์ดีขึ้นกว่าเคอร์เซอร์รุ่นก่อนหน้า

รูปที่แนบมาแสดงผลลัพธ์ของการทดสอบเกณฑ์มาตรฐานในdaวิธีใหม่UpdateCursor เทียบกับวิธี UpdateCursor เก่า เป็นหลักสคริปต์ดำเนินการเวิร์กโฟลว์ต่อไปนี้:

  1. สร้างคะแนนสุ่ม (10, 100, 1,000, 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. กำจัดชั้นของนามธรรม:การดำเนินการเริ่มต้นของเคอร์เซอร์งูใหญ่อยู่บนพื้นฐานเก่าส่ง / COM ตาม GPDispatch วัตถุซึ่งเปิดใช้งานหนึ่งที่จะใช้API ที่เดียวกันในภาษาใด ๆ ที่อาจใช้วัตถุ COM ส่ง ซึ่งหมายความว่าคุณมี API ที่ไม่ได้โดยเฉพาะอย่างยิ่งที่ดีที่สุดสำหรับสภาพแวดล้อมใด ๆ เดียว แต่มันก็หมายความว่ามีอยู่เป็นจำนวนมากของชั้นของนามธรรมสำหรับวัตถุ COM ในการโฆษณาและวิธีการแก้ปัญหาที่รันไทม์ยกตัวอย่างเช่น ถ้าคุณจำก่อน ArcGIS 9.3 มันเป็นไปได้ที่จะเขียนสคริปต์ Geoprocessing ใช้ที่ clunky อินเตอร์เฟซเดียวกันหลายภาษาแม้ Perl และทับทิม เอกสารเพิ่มเติมที่วัตถุต้องทำเพื่อจัดการกับIDispatch สิ่งที่เพิ่มความซับซ้อนและชะลอการเรียกใช้ฟังก์ชัน
  2. สร้างไลบรารี C ++ เฉพาะเจาะจงของ Python ที่มีการผสมผสานอย่างแน่นหนาโดยใช้สำนวน Pythonic และโครงสร้างข้อมูล:ความคิดเกี่ยวกับRowวัตถุและการwhile cursor.Next():เต้นแปลก ๆ จริงๆนั้นไม่มีประสิทธิภาพใน Python การดึงไอเท็มจากรายการเป็นการดำเนินการที่รวดเร็วมากและลดความซับซ้อนลงเหลือเพียงการเรียกใช้ฟังก์ชั่น CPython เพียงไม่กี่ครั้ง (โดยทั่วไปเป็นการ__getitem__โทร การทำrow.getValue("column")โดยการเปรียบเทียบนั้นมีน้ำหนักมากกว่า: มันจะ__getattr__ทำการดึงข้อมูลเมธอด (ซึ่งจำเป็นต้องสร้างวัตถุเมธอดที่ถูกผูกใหม่) จากนั้นเรียกเมธอดนั้นด้วยอาร์กิวเมนต์ที่กำหนด ( __call__) ส่วนหนึ่งของแต่ละarcpy.daการดำเนินงานเป็นอย่างมากแบบบูรณาการอย่างใกล้ชิดกับ CPython API ด้วย C ++ ที่ปรับด้วยมือจำนวนมากเพื่อทำให้มันรวดเร็วโดยใช้โครงสร้างข้อมูล Python ดั้งเดิม (และการรวมเข้าด้วยกันที่ไม่ซับซ้อนเช่นกันเพื่อความเร็วและประสิทธิภาพของหน่วยความจำที่มากยิ่งขึ้น)

คุณจะยังแจ้งให้ทราบว่าในเกือบทุกมาตรฐาน ( ดูภาพนิ่งเหล่านี้ตัวอย่างเช่น ) ArcObjects ในสุทธิและ C ++ ยังคงมีมากกว่าสองครั้งเร็วarcpy.daในการทำงานมากที่สุด ใช้รหัสไพ ธ อนarcpy.daเร็วกว่า แต่ก็ยังไม่เร็วกว่าภาษาที่คอมไพล์และเลเวลต่ำกว่า

TL; DR : daเร็วกว่าเนื่องจากdaมีการใช้งานใน Arcobjects / C ++ / CPython แบบตรงขึ้นซึ่งไม่ได้รับการปรับแต่งซึ่งออกแบบมาโดยเฉพาะเพื่อให้ได้ผลลัพธ์ของรหัส Python ที่รวดเร็ว


4

ประสิทธิภาพที่เกี่ยวข้อง

  • เคอร์เซอร์วนซ้ำเท่านั้นผ่านรายการชุดเขตข้อมูลตามค่าเริ่มต้น (ไม่ใช่ฐานข้อมูลทั้งหมด)

อื่น ๆ ไม่เกี่ยวข้องกับประสิทธิภาพโดยตรง แต่มีการปรับปรุงที่ดี:

  • ความสามารถในการใช้โทเค็น (เช่น SHAPE @ LENGTH, SHAPE @ XY) สำหรับการเข้าถึงรูปทรงเรขาคณิตของคุณลักษณะ
  • ความสามารถในการเดินผ่านฐานข้อมูล (โดยใช้วิธีarcpy.da.Walk )
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.