1 votos

¿Utilizar el multiprocesamiento con el cursor de actualización?

Estoy tratando de utilizar el multiprocesamiento para ayudarme a ejecutar una herramienta que recorte una característica y sume un atributo en ella. La herramienta necesita iterar a través de unas 24.000 filas de una featureclass mientras hace esto. Puedo ejecutarla sin multiprocesamiento, pero tarda mucho tiempo (más de 20 horas). Por ello, estoy intentando utilizar el multiprocesamiento para que se ejecute más rápido, ya que es probable que tenga que volver a utilizar este tipo de herramienta con conjuntos de datos más grandes. Sin embargo, cuando lo ejecuto, se ejecuta y termina, pero no hay salida y cuando miro los shapefiles creados durante el mismo, el updatecursor no se ha ejecutado en ellos. Espero que alguien pueda ayudarme a codificar mejor para que funcione.

import arcpy
import os
import multiprocessing

#this toolbox is full of tools I've made, I use one of them later
arcpy.ImportToolbox( 
r'C:\Users\joe.chestnut\Documents\PythonScripts\JoesTools.pyt')
#geodatabase that my files are all in
arcpy.env.workspace = r"D:\Joe.Chestnut\Dallas\Dallas.gdb"

#This is the actual function that I need to run.  
def ClipCount(stuffpassed):
    #ranges are based on the oid.  they stratify the data so that it can be multiprocessed. 
    ranges = stuffpassed[0]
    #this is my file with about 25,000 polygon features (service areas for census blocks in Dallas
    inputfile = stuffpassed[1]
    #This file is the census blocks in dallas, and has some job data in it
    inputfile2 = stuffpassed[2]
    print(ranges)
    print"RunningClipCount)"
    arcpy.env.workspace =r"D:\Joe.Chestnut\Dallas" 
    i, j = ranges[0], ranges[1]
    #This copies my file into a folder and creates 4 different copies of it, for the four different processors to run on
    infile = arcpy.management.CopyFeatures(inputfile,  'layer{0}'.format(i), """OID>= {0} AND OID <= {1}""".format(i, j))
    print(infile)
    #makes a layer out of my census blocks so that they can be geoprocessed
    cliplayer = arcpy.management.MakeFeatureLayer(inputfile2, "clipmedallas")
    print(cliplayer)
    #this cursor runs through each of the rows of the service areas file, and for each one will clip
    #the census block file.  Using a searchcursor on the clipped output, it will then sum the values in the 'newpop' field
    #the summed values are then written into the 'jobcount' field of the service area file using the update cursor. 
    with arcpy.da.UpdateCursor(infile, ["Name", "jobcount"]) as cursor:
        print "updatecursorrunning"
        for row in cursor:
            value = row[0]
            field = "Name"
            exp = field+"='" + value + "'"
            infile3 = arcpy.MakeFeatureLayer_management(infile, "infile3")
            rowselect = arcpy.SelectLayerByAttribute_management(infile3, "NEW_SELECTION", exp)
            clipedlyr = arcpy.LEHDClipper(cliplayer, rowselect, "in_memory", "in_memory\clipedlyr")
            with arcpy.da.SearchCursor(clipedlyr, "newpop") as newcursor:
                stationpop = []
                for srow in newcursor:
                    value = float(srow[0])
                    stationpop.append(value)

                print(stationpop)

            totalpop= 0
            for num in stationpop:
                totalpop = totalpop + num

            print(totalpop)
            row[1] = totalpop
            cursor.updateRow(row)
            arcpy.Delete_management(clipedlyr)
#This is the main function where I give the inputs for the ClipCount and then actually run the multiprocessing module. 
def main():

    ranges = [[1, 6000], [6001, 12000], [12001, 18000], [18001, 24000]]
    inputfile =r'D:\Joe.Chestnut\Dallas\Dallas.gdb\gtfs\BlockAccess'
    inputfile2 = r'D:\Joe.Chestnut\Dallas\Dallas.gdb\gtfs\Dallas_1clip'
    stuffpassed = [ranges, inputfile, inputfile2]
    pool = multiprocessing.Pool(processes=4, initializer=None, maxtasksperchild = 1)
    result = pool.map_async(ClipCount, stuffpassed)
    pool.close()
    pool.join()    

    print result

if __name__ == '__main__':
    main()

Cuando ejecuto esto, obtengo el siguiente resultado:

<multiprocessing.pool.MapResult object at 0x1467CAD0>

También crea cuatro copias del archivo de entrada como shapefiles. Sin embargo, aparte de esto, no creo saber si está haciendo algo.

¿Alguien sabe qué estoy haciendo mal?

¿Cómo consigo que el cursor de actualización se ejecute con el multiprocesamiento?

3voto

August Karlstrom Puntos 445

Mi respuesta no se refiere a la resolución de tu problema con el multiprocesador, sino al enfoque general para contar las partes superpuestas. Aconsejé un método usando la unión espacial en este respuesta a ¿Cómo eliminar características duplicadas con la misma geometría en ArcMap? que utiliza el operador 'ARE_IDENTICAL' con la asignación de campos. En resumen, si se autoune la entrada, mantendrá todas las partes que se solapen y luego la unión espacial encontrará las idénticas y las contará.

0voto

ollybee Puntos 558

Tu llamada de multiprocesamiento está mal, que es el quid (o al menos la primera parte) de tu problema. No tengo ni idea de cómo estás consiguiendo cuatro copias del archivo de entrada, ya que parece que sólo deberías hacer 3, una por cada elemento de tu lista stuffpassed malformada.

Map_async debería hacer una llamada por cada elemento de la lista de argumentos, así que tu código actual sólo debería ejecutar clipcount 3 veces (una por cada elemento de tu lista actual de Stuffpassed). También está fallando porque estás diciendo obtener oid entre dos rangos que son dos listas no dos números. Así que cómo arreglar esto:

Stuffpassed no está en absoluto correctamente formateado para una llamada multiproceso map_async. Si quiere mantener la forma en que está analizando las variables dentro de clipcount necesita que stuffpassed sea una lista de listas con cada elemento de la lista exterior siendo TODAS las variables que desea pasar a cada llamada de clipcount.

Esto significa que necesitas que stuffpassed esté vacío y luego necesitas hacer un bucle a través de cada elemento de los rangos para rellenarlo.

 stuffpassed = list()
 for range in ranges:
      stuffpassed.append([range,infile1,infile2])

Ahora tu llamada de multiprocesamiento estará, al menos, recibiendo las variables que necesita y que crees que estás enviando.

También estoy bastante seguro de que copyfeatures no devuelve nada y no se puede configurar infile de esa manera, pero podría estar equivocado al respecto.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X