##################### Developed by: Ken Carrier ######################
#### 01/26/2012
#### Use Multiprocessing with an UpdateCursor
#### Check Values in attribute table that point to files on the network
#### If the file path exist mark field as TRUE If not FALSE
######################################################################
import arcpy, multiprocessing, time
from arcpy import env
from multiprocessing import Pool
# Overwrites values if they already exist.
env.overwriteOutput = True
# Specify the object you will be working with.
inputFC = r"C:\temp\PythonScripts\Multiprocessing\IfExists\DC@GISADMIN@MCESDB@GIS.sde\GIS.GISADMIN.tmpTest"
# Limit the fields used in the cursor, by Default all field are used.
# If all fields are used it will slow down the process.
# "NET_PATH"=0, "EXST" = 1, "OBJECTID" = 2 'Notice whenever UCFields is called it is followed by [], the number
# corresponds to a field in the string array below.
UCFields = ["NET_PATH", "EXST", "OBJECTID"]
def FindValues(SQLQuery):
global inputFC
global UCFields
# Uncomment the line below to see the string that is being passed to the function.
## arcpy.AddMessage("SQL query being passed: " + SQLQuery)
# Prepare UpdateCursor
# inputFC = the object you will be working with.
# SQLQuery = a range of ObjectID's chunked out equally among processors or user defined processes.
# .join(UCFields) = limits the amount of fields seen by the cursor, limiting the fields increases performance.
# "OBJECTID A" = sorts the ObjectID field in Ascending Order.
rows = arcpy.UpdateCursor(inputFC, SQLQuery, "", "; ".join(UCFields), "OBJECTID A")
for row in rows:
if arcpy.Exists(row.getValue(UCFields[0])):
# Uncomment the line below to see the OBJECTID that is being processed
##arcpy.AddMessage(row.getValue(UCFields[2]))
# Process: Update the value to True if the item exists
row.setValue(UCFields[1], "TRUE")
rows.updateRow(row)
else:
# Uncomment the line below to see the OBJECTID that is being processed
##arcpy.AddMessage(row.getValue(UCFields[2]))
# Process: Update the value to False if the item does NOT exists
row.setValue(UCFields[1], "FALSE")
rows.updateRow(row)
# Process: Delete objects from memory
del rows, row
if __name__ == "__main__":
# Record the start time
arcpy.AddMessage("Started batch UpdateCursor job at: " + time.ctime())
# Uncomment the line below to evaluate the number of processors on the machine.
# This will be a multiple of available CPU cores multiplied by 3 minus 1
##partCount = int(os.environ["NUMBER_OF_PROCESSORS"]) * 2 - 1
# This is a user defined number of process you wish to use to split up the work
# This means the "the number of rows will be divided by 20 and that there will be 20 SQL queries for ranges
# of ObjectID's. You should see 20 python.exe processes in Task Manager.
partCount = 20
# Count the input table rows
#intputFC = r"C:\temp\PythonScripts\Multiprocessing\IfExists\DC@GISADMIN@MCESDB@GIS.sde\GIS.GISADMIN.tmpTest"
result = arcpy.GetCount_management(inputFC)
count = int(result.getOutput(0))
arcpy.AddMessage("Table: " + inputFC + " has rowcount " + str(count))
# Calculate the intervals suitable for a query ID >= <n> and ID < <n>
# based on the amount of rows in input table
intervals = range(1,count,int(count/partCount))
if len(intervals) > partCount:
intervals[-1] = count + 1
else:
intervals.append(count + 1)
# Create the queries for each table part.
# Get the OID,OBJECTID column name for the object you will be working with
desc = arcpy.Describe(inputFC)
OIDFieldName = desc.OIDFieldName
# Create a list of queries for OID ranges, as the queries are built they will be
# appended to this list
queryList = []
for i in range(len(intervals)-1):
queryList.append(OIDFieldName + " >= " + str(intervals[i]) + " AND " + OIDFieldName + " <= " + str(intervals[i+1]))
arcpy.AddMessage("Built query: " + queryList[i])
# Create a list which results will be appended to.
results = list();
# Tells python to create 20 processes
pool = Pool(processes=partCount);
# Send each query of OID ranges to the worker function as a seperate process.
for q in queryList:
results.append(pool.apply_async(FindValues, args = (q, )))
pool.close();
pool.join();
# Record the end time
arcpy.AddMessage("End batch UpdateCursor job at: " + time.ctime()