Pour commencer
Python 2.6, qui inclut le module multiprocessing, a été intégré aux produits ArcGIS à partir de la sortie d'ArcGIS 10.0 (version nationale d'ArcGIS 10.0 : 22 octobre 2010). Depuis lors, même sur le blog officiel d'Esri aux États-Unis,Multiprocessing Python – Approches et considérations (août 2011),Multiprocessing avec ArcGIS – Approches et considérations (Partie 1) : septembre 2012a été publié un article sur le traitement multiprocessus. Plus récemment, de nombreux développeurs du monde entier se réunissent au Esri Developer Summit oùParallel Python : Multiprocessing avec ArcPy : vidéo de mars 2017,Vector and Raster Multiprocessing avec ArcPy : vidéo de mars 2018ont été présentés comme sessions techniques.
Traitement multiprocessus
Environnement de travail ArcGIS ProAvec la généralisation des matériels à haute spécification (systèmes d'exploitation 64 bits standard, recommandation de CPU quad-core, mémoire optimale supérieure à 16 Go), les volumes de données utilisés pour l'analyse et le traitement augmentent considérablement, et la nécessité d’analyses et traitements efficaces persiste encore aujourd’hui.
Dans ce contexte, cette fois-ci, nous souhaitons présenter un exemple d’implémentation du traitement multiprocessus avec ArcPy et Python, qui est une méthode établie pour étendre la plateforme ArcGIS Pro, en expliquant les points clés et en illustrant par des exemples de code.
Pour le codage réel du traitement multiprocessus, nous vous recommandons de vérifier les informations connexes fournies et d’essayer d’écrire le code vous-même. En vous référant à cet article et en adoptant les points clés pour l’implémentation du traitement parallèle, cela pourra vous aider à intégrer efficacement cette fonctionnalité dans votre flux de travail actuel.
Exemple basique
Les documents liés indiquent que l’utilisation d’ArcPy et Python pour le traitement multiprocessus peut être résumée ainsi :
- Pour conserver les résultats temporaires et assurer une exécution rapide, il est recommandé d’utiliserl’espace de travail in_memory.
- Base de données fichier géodatabase (référence :Aperçu des bases de données fichier géodatabase) et éviter l’écriture dans un raster GRID.
Ces formats de données peuvent provoquer des problèmes liés au verrouillage ou à la synchronisation simultanée, car les bases de données fichier géodatabase et les rasters GRID ne supportent pas l’écriture simultanée. En résumé, un seul processus peut écrire à la fois. Lorsque vous modifiez une classe de fonctionnalités développée pour ArcGIS dans ArcPy, ce problème peut survenir. De plus, si vous possédez une base de données fichier géodatabase et tentez d’écrire dans plusieurs classes de fonctionnalités simultanément, ce problème s’amplifie. Même si chaque classe de fonctionnalités existe indépendamment, il n’est possible d’écrire dans une seule classe par base de données fichier géodatabase à la fois.
- Pour exécuter le script, utilisez un environnement Python 64 bits.
À partir d’ArcGIS Pro 1.4 ou ArcGIS Server 10.5 ou supérieur, ou si Background Geoprocessing (64-bit) est installé sur ArcGIS Desktop 10.5 ou supérieur, vous pouvez utiliser un environnement Python 64 bits. L’environnement 64 bits peut résoudre les problèmes liés aux limites mémoire (4 Go) rencontrés en 32 bits avec de grandes quantités de données. En particulier lors de l’implémentation, il faut faire attention à l’utilisation des bases de données fichier géodatabase mentionnées au point 2. Il est conseillé d’éviter d’utiliser la même base de données fichier géodatabase comme destination d’écriture dans plusieurs processus via des fonctions worker distinctes ; cependant, il est possible d’utiliser ces fonctions worker pour fusionner plusieurs fichiers ou bases de données fichier géodatabase en une seule source.
* Une autre méthode consiste à utiliser une base de données fichier géodatabase temporaire comme destination d’écriture dans la fonction worker pour plusieurs processus.
Exemple de traitement multiprocessus
L’exemple actuel contient plusieurs fichiers shapefile répartis sous les dossiers correspondant aux 47 préfectures japonaises. Après avoir créé une base de données fichier géodatabase pour chaque préfecture parmi ces 47 dossiers, le code implémente un échantillon qui convertit chacun en classe de fonctionnalités correspondante. Le point important lors de l’implémentation est que comme indiqué dans l’exemple basique ci-dessus, l’écriture vers la base de données fichier géodatabase est verrouillée lors de l’écriture ; donc « écrire un code qui convertit un shapefile par dossier préfecture en une classe dans la base de données fichier géodatabase correspondante ».
Examinons le modèle du code réel.
1) Fonction worker : batch_convert
Comme modèle du code réel, commençons par écrire la fonction worker similaire au traitement habituel avec ArcPy. Il faut noter que comme indiqué dans l’exemple basique, ce traitement correspond au traitement en processus unique ; si vous devez accéder à plusieurs processus (plusieurs fonctions worker), il faut utiliser une base de données fichier géodatabase temporaire ou éviter d’utiliser la même base comme destination d’écriture.
<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">'''
Traitement exécuté dans un seul processus (fonction worker) :
L’écriture vers la base de données fichier géodatabase ne peut pas être faite par plusieurs processus simultanément donc
- Plusieurs fichiers shapefile sous les dossiers correspondant aux préfectures japonaises
- Conversion en classes de fonctionnalités multiples sous la base donnée fichier géodatabase correspondante à chaque préfecture japonaise
'''</SPAN>
<SPAN class="comment token">#print("Conversion: {0} ⇒ {1}\n".format(inws,outws))</SPAN>
<SPAN class="keyword token">if</SPAN> <SPAN class="operator token">not</SPAN> arcpy.Exists<SPAN class="punctuation token">(</SPAN>outws<SPAN class="punctuation token">):</SPAN>
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 <SPAN class="keyword token">in</SPAN> fcs:
l=len(fc)
infc=os.path.splitext(fc)[0]
<SPAN class="comment token"># Modifier le nom des classes en supprimant les 4 premiers caractères</SPAN>
<SPAN class="comment token"># Ex : P101_CITY.shp → P0101_CITY</SPAN>
newfc = fc[:1]+fc[1:l-4].zfill(4)
<SPAN class="comment token"># Si la classe existe déjà faire Append</SPAN>
<SPAN class="comment token"># Sinon 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">sinon</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">" Conversion terminée : {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) Boucle de la fonction worker : multi_run_batch_convert
Lors de la spécification d'une fonction worker à partir d'un multi-processus, il n'est pas nécessaire de passer un seul argument à la fonction worker, mais lorsqu'il est nécessaire de passer plusieurs arguments comme un tuple, il est pratique d'utiliser une fonction 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 pour batch_convert :
Wrapper pour passer plusieurs arguments à la fonction d'exécution
'''</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) Traitement du multi-processus : exec_batch_convert
Les deux arguments (inws, outws) passés à la fonction worker sont mis sous forme de liste dans params.
Ensuite,
pool = multiprocessing.Pool(cpu_cnt) garantit un pool
results = pool.map(multi_run_batch_convert , params) est spécifié.
Premier argument : nom de la fonction worker à traiter (dans ce cas, la fonction wrapper) multi_run_batch_convert
Deuxième argument : params sous forme de liste de paramètres
<span class="keyword token">def</span> <span class="token function">exec_batch_convert</span>(infolder,outfolder)<span class="punctuation token">:</span>
<span class="string token">'''
Traitement en multi-processus (fonction master) :
'''</span>
<span class="keyword token">try</span>:
start=datetime.datetime.now()
<span class="keyword token">print</span> "-- Début : Multiprocess_ShapefileToFeatureClassWithRename --:",start
cpu_cnt=multiprocessing.cpu_count()
arcpy.env.workspace = infolder
inwss = arcpy.ListWorkspaces("*","Folder")
# Convertir les paramètres à passer à chaque processus en liste
params=[]
<span class="keyword token">for</span> inws <span class="keyword token">in</span> inwss:
param1=inws <span class="comment token"># Dossier préfecture (contenant les fichiers shapefile)</span>
gdbname=<span class="string token">"{0}.gdb"</span>.format(os.path.basename(inws))
param2=os.path.join(outfolder,gdbname) <span class="comment token"># Base de données géodatabase préfecture</span>
params.append((param1,param2))
<span class="keyword token">if</span> len(inwss) < cpu_cnt: <span class="comment token"># Si le nombre de dossiers à traiter est inférieur au nombre de CPU, inutile de lancer des processus inutiles</span>
cpu_cnt=len(inwss)
pool = multiprocessing.Pool(cpu_cnt) <span class="comment token"># Créer des processus python selon le nombre de CPU</span>
results=pool.map(multi_run_batch_convert,params) <span class="comment token"># Les processus sont exécutés séquentiellement par répartition</span>
pool.close()
pool.join()
# Sortie des résultats du traitement dans chaque processus
<span class="keyword token">for</span> r <span class="keyword token">in</span> results:
<span class="keyword token">print</span>(r)
# Fusionner les classes Feature dans la géodatabase par préfecture par dossier
# Notez ici si vous créez une version nationale complète
# ~省略~
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">" Temps écoulé :"<\/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><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><\/PAN...
Code d'exemple de la version terminée
J'ai modifié infolder et outfolder dans le script Python (Multiprocess_Sample.py) que j'ai implémenté conformément aux paramètres de codage ci-dessus, et si vous l'exécutez depuis l'environnement d'exécution Python, la conversion des données sera effectuée en multiprocessus.
<span class="comment token">#coding:cp932</span>
<span class="keyword token">import</span> arcpy<span class="punctuation token">,</span>os
<span class="keyword token">import</span> sys
<span class="keyword token">import</span> multiprocessing
<span class="keyword token">import</span> datetime
<span class="keyword token">import</span> traceback
reload<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 class="punctuation token">)</span>
<span class="keyword token">def</span> <span class="token function">multi_run_batch_convert</span><span class="punctuation token">(</span>args<span class="punctuation token">):</span>
<span class="string token">'''
wrapper de batch_convert :
un wrapper pour passer plusieurs arguments au traitement d'exécution en parallèle
'''</span>
<span class="keyword token">return</span> batch_convert<span class="punctuation token">(*</span>args<span class="punctuation token">)</span>
<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">'''
Traitement exécuté par un seul processus (fonction worker) :
L'écriture dans la géodatabase du fichier ne peut pas être faite par plusieurs processus simultanément, donc
on traite plusieurs fichiers shapefile sous une préfecture,
on convertit plusieurs fichiers shapefile sous une préfecture en classes de fonctionnalités dans la géodatabase,
comme décrit ici.
'''</span>
<span class="comment token">#print("Conversion : {0} 12; {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></span></code></pre>
outfolder<span class=\"operator\" >=<\//code></pre>
outfolder = os.path.dirname(outws)
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 = os.path.basename(outws)
arcpy.CreateFileGDB_management(outfolder, foldername, "CURRENT")
arcpy.env.workspace = inws
fcs = arcpy.ListFeatureClasses()
for fc in fcs:
l = len(fc)
infc = os.path.splitext(fc)[0]
# Modifier le nom de la classe de fonctionnalités pour les 4 derniers caractères enterrés
# Exemple) P101_CITY.shp → P0101_CITY
newfc = fc[:1] + fc[1:l-4].zfill(4)
# Si la classe de fonctionnalités existe déjà, faire Append
# Sinon, faire FeatureClassToFeatureClass
if arcpy.Exists(os.path.join(outws, newfc)):
outfc = os.path.join(outws, newfc)
arcpy.Append_management(fc, outfc)
else:
arcpy.FeatureClassToFeatureClass_conversion(fc, outws, newfc)
del fcs
return " Conversion terminée :{0}".format(outws)
<span class=\"keyword\" >def</span > exec_batch_convert(infolder,outfolder):
'''
Traitement en multiprocessus (fonction master) :
'''
<SPAN class="keyword token">essayer</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">"-- Début : 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 les paramètres à transmettre à chaque processus en liste</SPAN>
params<SPAN class="operator token">=</SPAN><SPAN class="punctuation token">[]</SPAN>
<SPAN class="keyword token">pour</SPAN> inws <SPAN class="keyword token">dans</span> inwss<SPAN class="punctuation token">:</span>
param1<SPAN class="operator token">=</SPAN>inws <SPAN class="comment token"># Dossier préfecture (contenant les fichiers shapefile)</span>
gdbname<SPAN class="operator token">=</SPAN><SPAN class="string token">"{0}.gdb"</span>.format(os.path.basename(inws))
param2<SPAN class="operator token">=</span>os.path.join(outfolder, gdbname) <span class="comment token"># Dossier de destination de la géodatabase préfecture</span>
params.append((param1, param2))
<span class="keyword token">si</span> len(inwss) < span class="operator token">< </span> cpu_cnt<span class="punctuation token">:</span> <span class="comment token"># Si le nombre de dossiers à traiter est inférieur au nombre de CPU, pas besoin de lancer des processus inutiles</span>
cpu_cnt = len(inwss)
pool = multiprocessing.Pool(cpu_cnt) <span class="comment token"># Créer un pool de processus Python selon le nombre de CPU</span>
results = pool.map(multi_run_batch_convert, params) <span class="comment token"># Exécuter séquentiellement dans les processus assignés</span>
pool.close()
pool.join()
<span class="comment token"># Sortie des résultats du traitement par processus</span>
<span class="keyword token">pour</span> r <span class="keyword token">dans</span> results<span class="punctuation token">:</span>
print(r)
<span class="comment token"># Fusionner les classes Feature dans la géodatabase par préfecture</span>
<span class="comment token"># Noter ici si création d'une version nationale complète</span>
<span class="comment token"># ~省略~</span>
fin = datetime.datetime.now()
print "-- Fin : Multiprocess_ShapefileToFeatureClassWithRename --:", fin
print " Temps écoulé :", fin - start
<span class="keyword token">sauf</span><span class="punctuation token">:</span>
print traceback.format_exc(sys.exc_info()[2])
<span class="keyword token">def</span> setup_batch_convert():
<span class="string token">'''
Définir les paramètres d'exécution depuis la ligne de commande :
Dossier source contenant les dossiers shapefile par préfecture : infolder
Exemple)
|-Shapefiles
|- 01_Hokkaido
|-P101_CITY.shp
|-L102_RIVER.shp
•••••
|- 02_Aomori-ken
|- 03_Iwate-ken
•••••
Dossier destination pour la création des géodatabases par préfecture : outfolder
Exemple)
|-Filegdbs
|- 01_Hokkaido.gdb
|-P0101_CITY
|-L0102_RIVER
•••••
|- 02_Aomori-ken.gdb
|- 03_Iwate-ken.gdb
•••••
'''</span>
infolder = r"E:\DATA\Shapefiles" <span class="comment token"># Dossier source contenant les dossiers shapefile par préfecture</span>
outfolder = r"E:\DATA\Filegdbs" <span class="comment token"># Dossier destination pour la création des géodatabases par préfecture</span>
exec_batch_convert(infolder, outfolder)
<span class="keyword token">si</span> __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>
Exemples d'exécution de scripts Python dans un environnement 64 bits
Veuillez exécuter depuis un environnement Python 64 bits, comme indiqué dans le best practice. Nous incluons des exemples d'exécution de scripts Python avec ArcGIS Desktop et ArcGIS Pro.
Exemple d'exécution) ArcGIS Desktop 10.6.1
>C:\Python27\ArcGISx6410.6\python.exe Multiprocess_Sample.py
Exemple d'exécution) ArcGIS Pro 2.2
>"c:\Program Files\ArcGIS\Pro\bin\Python\scripts\propy.bat" Multiprocess_Sample.py
Blogs et sites Web de référence
・Utiliser Arcpy avec multiprocessing – Partie 1・Utiliser Arcpy avec multiprocessing – Partie 2・Utiliser Arcpy avec multiprocessing – Partie 3・Multiprocessing en Python – Approches et considérations (août 2011 : environnement ArcGIS 10.0)・Multiprocessing avec ArcGIS – Approches et considérations (Partie 1) (septembre 2012 : environnement ArcGIS 10.1)・Matériel du laboratoire e-learning de John A. Dutton à l'Université d'État de Pennsylvanie GEOG 489 - Programmation Python avancée pour SIG - Exemples multiprocessing ArcPy 1.6.6
Vidéos de référence
・Parallel Python : Multiprocessing avec ArcPy (Esri Developer Summit, mars 2017)・Multiprocessing vectoriel et raster avec ArcPy (Esri Developer Summit, mars 2018)