Introducción
La inclusión del módulo multiprocessing en Python 2.6 dentro de los productos ArcGIS comenzó con la aparición de ArcGIS 10.0 (lanzamiento nacional de ArcGIS 10.0: 22 de octubre de 2010). Desde entonces, incluso en el blog oficial de Esri en EE.UU.Python Multiprocessing – Enfoques y Consideraciones (agosto de 2011),Multiprocessing con ArcGIS – Enfoques y Consideraciones (Parte 1): septiembre de 2012se publicaron artículos sobre procesamiento multiproceso, y en años recientes, muchos desarrolladores de todo el mundo se han reunido en la Esri Developer Summit paraParallel Python: Multiprocessing con ArcPy: video de marzo de 2017,Multiproceso Vectorial y Raster con ArcPy: video de marzo de 2018y se ha presentado como una sesión técnica.
Procesamiento multiproceso
Entorno operativo ArcGIS ProCon la popularización del hardware de alta especificación (sistemas operativos de 64 bits estándar, recomendación de CPU con 4 núcleos, memoria óptima superior a 16 GB), la cantidad de datos utilizados para análisis y procesamiento ha aumentado drásticamente, y la necesidad de análisis y procesamiento eficiente continúa vigente.
En este contexto, esta vez queremos presentar el procesamiento multiproceso con ArcPy y Python, que se está estableciendo como una extensión del ArcGIS platform, explicando los puntos clave de implementación junto con ejemplos de código.
Para el código real en procesamiento multiproceso, recomendamos verificar la información relacionada proporcionada y probar escribiendo código por su cuenta; sin embargo, esperamos que consulten este artículo para obtener puntos clave sobre la implementación paralela y que les ayude a integrarlo bien en sus flujos de trabajo actuales.
Ejemplo básico
En los diversos materiales relacionados mostrados, se menciona lo siguiente como ejemplo básico del procesamiento multiproceso usando ArcPy y Python.
- Para mantener los resultados temporales y acelerar el procesamiento,se recomienda usar in_memory workspace.
- Base de datos File Geodatabase (referencia:Resumen base de datos geográfica), evitar escribir en GRID raster.
Estos formatos pueden causar problemas con bloqueos y sincronización simultánea, por lo que File Geodatabase y GRID raster no soportan escritura simultánea; es decir, solo un proceso puede escribir a la vez. Cuando se intenta modificar clases feature abiertas en ArcGIS usando ArcPy, este problema puede surgir. Además, si se intenta escribir en muchas clases feature dentro de una File Geodatabase, el problema se amplía. Aunque cada clase feature existe independientemente, dentro del File Geodatabase solo una clase feature puede ser escrita a la vez.
- Para ejecutar scripts se debe usar un entorno Python de 64 bits.
Desde ArcGIS Pro 1.4 o ArcGIS Server 10.5 o posterior, o al instalar Background Geoprocessing (64-bit) para ArcGIS Desktop 10.5 o superior, se puede usar un entorno Python de 64 bits. El entorno de ejecución de 64 bits puede resolver problemas relacionados con límites de memoria (4GB) que ocurren en entornos de 32 bits con grandes volúmenes de datos. Especialmente para la implementación, hay que tener cuidado con el uso del File Geodatabase mencionado en segundo lugar. Se recomienda no usar el mismo File Geodatabase para escritura desde funciones worker que registran procesos en cada proceso; sin embargo, es posible usar funciones master para fusionar múltiples archivos shape o File Geodatabase individuales en una sola fuente.
* Como destino para escritura desde múltiples procesos o funciones worker, también es posible usar un Enterprise Geodatabase como destino para escritura.
Ejemplo de procesamiento multiproceso
El ejemplo actual contiene múltiples archivos shape bajo carpetas separadas por las 47 prefecturas japonesas; tras crear bases File Geodatabase por cada prefectura, implementa código que cambia cada archivo shape a su respectiva clase feature dentro del File Geodatabase. El punto clave al implementar es que al escribir en File Geodatabase está bloqueado durante la escritura; por ello el código indica "Escribir código para cambiar archivos shape bajo carpeta prefectura a clase feature dentro del File Geodatabase correspondiente".
Veamos el patrón real del código.
1) Función worker: batch_convert
Como patrón del código, primero escribe la función worker similar al procesamiento normal con ArcPy. Hay que tener cuidado porque el procesamiento con esta función worker corresponde al procesamiento en proceso; si es necesario acceder desde múltiples procesos (múltiples funciones worker), hay que usar Enterprise Geodatabase o evitar usar el mismo File Geodatabase.
<SPAN class="keyword token">def</SPAN> <SPAN class="token function">batch_convert</SPAN><SPAN class="punctuation token">(</SPAN>inws<SPAN class="punctuation token">,</SPAN> outws<SPAN class="punctuation token">):</SPAN>
<SPAN class="string token">'''
Procesamiento ejecutado por un proceso (función worker):
La escritura a File Geodatabase no puede hacerse desde múltiples procesos simultáneamente, por lo que
- múltiples archivos shape bajo carpetas separadas por prefectura japonesa
- cambio a clases feature dentro del File Geodatabase bajo carpeta prefectura japonesa
está registrado aquí
'''</SPAN>
<SPAN class="comment token">#print("Cambio: {0} ⇒ {1}\n".format(inws,outws))</SPAN>
<SPAN class="keyword token">if</SPAN> <SPAN class="operator token">not</SPAN> arcpy<SPAN class="punctuation token">.</SPAN>Exists<SPAN class="punctuation token">(</SPAN>outws<SPAN class="punctuation token">):</SPAN>
outfolder<SPAN class="operator token">=</SPAN>os<SPAN class="punctuation token">.</SPAN>path<SPAN class="punctuation token">.</SPAN>dirname<SPAN class="punctuation token">(</SPAN>outws<SPAN class="punctuation token">)</SPAN>
foldername<SPAN class="operator token">=</SPAN>os<SPAN class="punctuation token">.</SPAN>path<SPAN class="punctuation token">.</SPAN>basename<SPAN class="punctuation token">(</SPAN>outws<SPAN class="punctuation token">)</SPAN>
arcpy<SPAN class="punctuation token">.</SPAN>CreateFileGDB_management<SPAN class="punctuation token">(</SPAN>outfolder<SPAN class="punctuation token">,</SPAN>foldername<SPAN class="punctuation token">,"CURRENT"</SPAN><SPAN class="punctuation token">)</SPAN>
arcpy<SPAN class="punctuation token">.</SPAN>env<SPAN class="punctuation token">.</SPAN>workspace = inws
fcs = arcpy.ListFeatureClasses()
<SPAN class="keyword token">for</SPAN> fc <SPAN class="keyword token">in</SPAN> fcs:
l=len(fc)
infc=os.path.splitext(fc)[0]
<SPAN class="comment token"># Cambiar nombre clase feature truncando últimos 4 caracteres</SPAN>
<SPAN class="comment token"># Ejemplo) P101_CITY.shp → P0101_CITY</SPAN>
newfc = fc[:1]+fc[1:l-4].zfill(4)
<SPAN class="comment token"># Si ya existe clase feature hacer Append</SPAN>
<SPAN class="comment token"># Si no existe hacer FeatureClassToFeatureClass</SPAN>
<SPAN class="keyword token">si</SPAN> arcpy<SPAN class="punctuation token">.</SPAN>Exists<SPAN class="punctuation token">(</SPAN>os<SPAN class="punctuation token">.</SPAN>path<SPAN class="punctuation token">.</SPAN>join<SPAN class="punctuation token">(</SPAN>outws<SPAN class="punctuation token">,</SPAN>newfc<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN>
outfc<SPAN class="operator token">=</SPAN>os<SPAN class="punctuation token">.</SPAN>path<SPAN class="punctuation token">.</SPAN>join<SPAN class="punctuation token">(</SPAN>outws<SPAN class="punctuation token">,</SPAN>newfc<SPAN class="punctuation token">)</SPAN>
arcpy<SPAN class="punctuation token">.</SPAN>Append_management<SPAN class="punctuation token">(</SPAN>fc<SPAN class="punctuation token">,</SPAN>outfc<SPAN class="punctuation token">)</SPAN>
<SPAN class="keyword token">sino</SPAN><SPAN class="punctuation token">:</SPAN>
arcpy<SPAN class="punctuation token">.</SPAN>FeatureClassToFeatureClass_conversion<SPAN class="punctuation token">(</SPAN>fc<SPAN class="punctuation token">,</SPAN>outws<SPAN class="punctuation token">,</SPAN>newfc<SPAN class="punctuation token">)</SPAN>
<SPAN class="keyword token">del</SPAN> fcs
<SPAN class="keyword token">return</SPAN> <SPAN class="string token">" Conversión completada: {0}"</SPAN><SPAN class="punctuation token">.</SPAN>format<SPAN class="punctuation token">(</SPAN>outws<SPAN class="punctuation token">)</SPAN>
<SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></Span><Span> </Span><Span> </Span><Span> </Span><Span> </Span><Span> </Span><Span> </Span><Span> </Span><Span> </Span><Span> </Span><Span> </Span><Span> </Span><Span> </Span><Span> </Span><Span> </Span><Span> </Span><Span> </Span><Span> </Span><Span> </Span><Span> </Span></span>
2) Función wrapper para worker: multi_run_batch_convert
Al especificar la función worker desde un proceso múltiple, no es necesario pasar argumentos si la función worker tiene argumentos únicos, pero si necesita pasar múltiples argumentos, es conveniente usar una función wrapper.
<span class="keyword token">def</span> <span class="token function">multi_run_batch_convert</span>(args)<span class="punctuation token">:</span>
<span class="string token">'''
Wrapper para batch_convert:
Wrapper para pasar múltiples argumentos a la ejecución
'''</span>
<span class="keyword token">return</span> batch_convert<span class="punctuation token">(*</span>args<span class="punctuation token">)</span><<EMOJI_33><span class="line-numbers-rows"><span><<EMOJI_34></span><span><<EMOJI_35></span><span><<EMOJI_36></span><span><<EMOJI_37></span><span><<EMOJI_38></span><span><<EMOJI_39></span></span>
3) Procesamiento de multiproceso: exec_batch_convert
Se convierte a lista el parámetro params con dos argumentos (inws, outws) que se pasan a la función worker.
Luego,
se asegura el pool con multiprocessing.Pool(cpu_cnt)
Se especifica results = pool.map(multi_run_batch_convert , params).
Primer argumento: nombre de la función worker a procesar (en este caso la función wrapper) multi_run_batch_convert
Segundo argumento: parámetros pasados en forma de lista params
<span class="keyword token">def</span> <span class="token function">exec_batch_convert</span>(infolder<span class="punctuation token">,</span> outfolder)<span class="punctuation token">:</span>
<span class="string token">'''
Procesamiento multiproceso (función master):
'''</span>
<span class="keyword token">try</span>:
start<span class="operator token">=</span>datetime<span class="punctuation token">.</span>datetime<span class="punctuation token">.</span>now<span class="punctuation token">()</span>
<span class="keyword token">print</span> "-- Inicio: Multiproceso_ShapefileToFeatureClassWithRename --:", start
cpu_cnt<span class="operator token">=</span>multiprocessing<span class="punctuation token">.</span>cpu_count<span class="punctuation token">()</span>
arcpy<span class="punctuation token">.</span>env<span class="punctuation token">.</span>workspace = infolder
inwss = arcpy<span class="punctuation token">.</span>ListWorkspaces("*","Folder")
# Convertir parámetros para cada proceso a lista
params=[]
<span class="keyword token">for</span> inws <span class="keyword token">in</span> inwss:
param1=inws <span class="comment token"># Carpeta prefectural (contiene shapefiles)</span>
gdbname=<span class="string token">"{0}.gdb"</span>.format(os.path.basename(inws))
param2=os.path.join(outfolder,gdbname) <span class="comment token"># Geodatabase de carpeta prefectural</span>
params.append((param1,param2))
<span class="keyword token">if</span> len(inwss) < cpu_cnt: <span class="comment token"># Si el número de carpetas a procesar es menor que los núcleos CPU, no iniciar procesos innecesarios</span>
cpu_cnt=len(inwss)
pool = multiprocessing.Pool(cpu_cnt) <span class="comment token"># Crear procesos python según núcleos CPU disponibles</span>
results=pool.map(multi_run_batch_convert,params) <span class="comment token"># Ejecutar procesos en orden asignado por división de tareas</span>
pool.close()
pool.join()
# Salida de resultados del procesamiento en cada proceso
<span class="keyword token">for</span> r <span class="keyword token">in</span> results:
<span class="keyword token">print</span>(r)
# Unificar clases feature dentro de la geodatabase por carpeta prefectural
# Aquí se anotaría si se crea versión nacional completa
# ~省略~
fin<SPAN class="operator token">=<\/SPAN>datetime<SPAN class="punctuation token">.<\/SPAN>datetime<SPAN class="punctuation token">.<\/SPAN>now<SPAN class="punctuation token">(<\/SPAN><SPAN class="punctuation token">)<\/SPAN>
<SPAN class="keyword token">print<\/SPAN> <SPAN class="string token">"-- Fin: Multiprocess_ShapefileToFeatureClassWithRename --:"<\/SPAN><SPAN class="punctuation token">,<\/SPAN>fin
<SPAN class="keyword token">print<\/SPAN> <SPAN class="string token">" Tiempo transcurrido:"<\/SPAN><SPAN class="punctuation token">,<\/SPAN> fin<SPAN class="operator token">-<\/SPAN>start
<SPAN class="keyword token">except<\/SPAN><SPAN class="punctuation token">:<\/SPAN>
<SPAN class="keyword token">print<\/SPAN> traceback<SPAN class="punctuation token">.<\/SPAN>format_exc<SPAN class="punctuation token">(<\/SPAN>sys<SPAN class="punctuation token">.<\/SPAN>exc_info<SPAN class="punctuation token">(<\/SPAN><SPAN class="punctuation token">)<\/SPAN><SPAN class="punctuation token">[<\/SPAN><SPAN class="number token">2<\/SPAN><SPAN class="punctuation token">]<\/SPAN><SPAnclass="line-numbers-rows"><SPAn><\/SPAn><SPAn><\/SPAn><SPAn><\/SPAn><SPAn><\/SPAn><SPAn><\/SPAn><SPAn><\/SPAn><SPAn><\/SPAn><SPAn><\/SPAn><SPAn><\/SPAn><SPAn><\/SPAn><SPAn><\/SPAn><SPAn><\/SPAn><SPAn><\/SPAn><SPAn><\/SPAn><SPAn><\/SPAn><SPAn><\/SPAn><SPAn><\/SPAn><SPAn><\/SPAn><SPAn><\/SPAn><SPAn><\/SPAn><SPAn><\/SPAn><SPAn></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
Código de muestra de la versión completa
He modificado los parámetros infolder y outfolder del script Python implementado (Multiprocess_Sample.py) según el código anterior para que, si se ejecuta desde el entorno de ejecución de Python, la conversión de datos se realice en multiproceso.
<SPAN class="comment token">#coding:cp932<\/SPAN>
<SPAN class="keyword token">importar<\/SPAN> arcpy<SPAN class="punctuation token">,<\/SPAN>os
<SPAN class="keyword token">importar<\/SPAN> sys
<SPAN class="keyword token">importar<\/SPAN> multiprocessing
<SPAN class="keyword token">importar<\/SPAN> datetime
<SPAN class="keyword token">importar<\/SPAN> traceback
recargar<SPAN class="punctuation token">(<\/SPAN>sys<SPAN class="punctuation token">)<\/SPAN>
sys<SPAN class="punctuation token">.<\/SPAN>setdefaultencoding<SPAN class="punctuation token">(<\/Span>'cp932'<Span>)</Span>
<Span class='keyword token'>def</Span> <Span class='token function'>multi_run_batch_convert</Span>(args):
'''
wrapper de batch_convert:
un wrapper para pasar múltiples argumentos al procesamiento paralelo
'''</Span>
<Span class='keyword token'>return</Span> batch_convert(*args)
<Span class='keyword token'>def</Span> <Span class='token function'>batch_convert</Span>(inws, outws):
'''
procesamiento que se ejecuta en un solo proceso (función worker):
debido a que no es posible escribir en una base de datos geográfica con múltiples procesos,
múltiples shapefiles bajo una prefectura o estado
múltiples clases de entidad bajo una base de datos geográfica en una prefectura o estado
están descritos para convertir
'''</Span>
<Span class='comment token'>#print("Conversión: {0} => {1}\n".format(inws,outws))</Span>
<Span class='keyword token'>if</Span> not arcpy.Exists(outws):
outfolder=os.path.dirname(outws)
foldername=os.path.basename(outws)
arcpy.CreateFileGDB_management(outfolder, foldername, "CURRENT")
arcpy.env.workspace = inws
fcs = arcpy.ListFeatureClasses()
<Span class='keyword token'>for</Span> fc in fcs:
l=len(fc)
infc=os.path.splitext(fc)[0]
<Span class='comment token'># Cambiar el nombre de la clase de entidad para los últimos 4 caracteres enterrados</Span>
<Span class='comment token'># Ejemplo) P101_CITY.shp → P0101_CITY</Span>
newfc = fc[:1]+fc[1:l-4].zfill(4)
<Span class='comment token'># Si la clase de entidad ya existe, usar Append</Span>
<Span class='comment token'># Si no existe, usar FeatureClassToFeatureClass</Span>
<Span class='keyword token'>if</Span> arcpy.Exists(os.path.join(outws,newfc)):
outfc=os.path.join(outws,newfc)
arcpy.Append_management(fc,outfc)
<Span class='keyword token'>else</Span>:
arcpy.FeatureClassToFeatureClass_conversion(fc,outws,newfc)
<Span class='keyword token'>del</Span> fcs
<Span class='keyword token'>return</Span> " Conversión terminada: {0}".format(outws)
<Span class='keyword token'>def</Span> <Span class='token function'>exec_batch_convert</Span>(infolder,outfolder):
'''
procesamiento en multiproceso (función master):
'''
<SPAN class="keyword token">intentar</SPAN><SPAN class="punctuation token">:</SPAN>
start<SPAN class="operator token">=</SPAN>datetime<SPAN class="punctuation token">.</SPAN>datetime<SPAN class="punctuation token">.</SPAN>now<SPAN class="punctuation token">()</SPAN>
<SPAN class="keyword token">print</SPAN> <SPAN class="string token">"-- Inicio: Multiprocess_ShapefileToFeatureClassWithRename --:"</SPAN><SPAN class="punctuation token">,</SPAN>start
cpu_cnt<SPAN class="operator token">=</SPAN>multiprocessing<SPAN class="punctuation token">.</SPAN>cpu_count<SPAN class="punctuation token">()</SPAN>
arcpy<SPAN class="punctuation token">.</SPAN>env<SPAN class="punctuation token">.</SPAN>workspace <SPAN class="operator token">=</SPAN> infolder
inwss <SPAN class="operator token">=</SPAN> arcpy<SPAN class="punctuation token">.</SPAN>ListWorkspaces<SPAN class="punctuation token">("*","Folder")</SPAN>
<SPAN class="comment token"># Convertir los parámetros para pasar a cada proceso</SPAN>
params<SPAN class="operator token">=</SPAN><SPAN class="punctuation token">[]</SPAN>
<SPAN class="keyword token">para</SPAN> inws <SPAN class="keyword token">en</SPAN> inwss<SPAN class="punctuation token">:</SPAN>
param1<SPAN class="operator token">=</SPAN>inws <SPAN class="comment token"># Carpeta de prefectura (contiene archivos shapefile)</SPAN>
gdbname<SPAN class="operator token">=</SPAN><SPAN class="string token">"{0}.gdb"</SPAN><SPAN class="punctuation token">.</SPAN>format<SPAN class="punctuation token">(os.path.basename(inws))</SPAN>
param2<SPAN class="operator token">=</SPAN>os.path.join(outfolder,gdbname) <SPAN class="comment token"># Carpeta destino para la geodatabase de la prefectura</SPAN>
params.append((param1,param2))
<SPAN class="keyword token">si</SPAN> len(inwss) < <span class="operator token">cpu_cnt</span>: <span class="comment token"># Si el número de carpetas es menor que los núcleos CPU, no iniciar procesos innecesarios</span>
cpu_cnt = len(inwss)
pool <span class="operator token">=</span> multiprocessing.Pool(cpu_cnt) <span class="comment token"># Crear procesos Python según núcleos CPU disponibles</span>
results = pool.map(multi_run_batch_convert,params) <span class="comment token"># Ejecutar en orden asignado a cada proceso</span>
pool.close()
pool.join()
<span class="comment token"># Salida de resultados del procesamiento en cada proceso</span>
para r en results:
print(r)
<span class="comment token"># Unificar clases feature dentro de la geodatabase por prefectura</span>
<span class="comment token"># Para crear versión nacional, anotar aquí</span>
<span class="comment token"># ~省略~</span>
fin = datetime.datetime.now()
print "-- Fin: Multiprocess_ShapefileToFeatureClassWithRename --:",fin
print " Tiempo transcurrido:", fin-start
<span class="keyword token">except</span><span class="punctuation token">:</span>
print traceback.format_exc(sys.exc_info()[2])
def setup_batch_convert():
'''
Configurar parámetros de ejecución desde el comando prompt:
Carpeta origen con archivos shapefile por prefectura :infolder
Ejemplo)
|-Shapefiles
|- 01_Hokkaido
|-P101_CITY.shp
|-L102_RIVER.shp
・・・・・・
|- 02_AomoriPrefecture
|- 03_IwatePrefecture
・・・・・・
Carpeta destino para crear geodatabases por prefectura :outfolder
Ejemplo)
|-Filegdbs
|- 01_Hokkaido.gdb
|-P0101_CITY
|-L0102_RIVER
・・・・・・
|- 02_AomoriPrefecture.gdb
|- 03_IwatePrefecture.gdb
・・・・・・
'''</span>
infolder=r"E:\DATA\Shapefiles" <span class="comment token"># Carpeta origen con archivos shapefile por prefectura</span>
outfolder=r"E:\DATA\Filegdbs" <span class="comment token"># Carpeta destino para crear geodatabases por prefectura</span>
exec_batch_convert(infolder,outfolder)
if __name__ == '__main__':
setup_batch_convert<SPAN class="punctuation token">(<\/SPAN><SPAN class="punctuation token">)<\/SPAN><SPAN class="line-numbers-rows"><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN></SPAN></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
Ejemplo de ejecución de script Python en entorno de 64 bits
Nota: Como se escribió en el best practice, ejecute desde un entorno Python de 64 bits. Se incluyen ejemplos de ejecución de scripts Python en ArcGIS Desktop y ArcGIS Pro.
Ejemplo de ejecución) ArcGIS Desktop 10.6.1
>C:\Python27\ArcGISx6410.6\python.exe Multiprocess_Sample.py
Ejemplo de ejecución) ArcGIS Pro 2.2
>"c:\Program Files\ArcGIS\Pro\bin\Python\scripts\propy.bat" Multiprocess_Sample.py
Blogs y sitios web de referencia
·Uso de Arcpy con multiprocessing – Parte 1·Uso de Arcpy con multiprocessing – Parte 2·Uso de Arcpy con multiprocessing – Parte 3·Multiprocesamiento en Python – Enfoques y consideraciones (Agosto 2011: entorno ArcGIS 10.0)·Multiprocesamiento con ArcGIS – Enfoques y consideraciones (Parte 1) (Septiembre 2012: entorno ArcGIS 10.1)·Material del laboratorio de eLearning John A. Dutton de la Universidad Estatal de Pensilvania GEOG 489 - Programación avanzada en Python para GIS - Ejemplos de multiprocesamiento con ArcPy 1.6.6
Videos de referencia
·Parallel Python: Multiprocessing con ArcPy (Summit para desarrolladores Esri, marzo 2017)·Multiprocesamiento vectorial y raster con ArcPy (Summit para desarrolladores Esri, marzo 2018)