Une exigence courante dans le SIG est d'appliquer un outil de traitement à un certain nombre de fichiers ou d'appliquer un processus pour un certain nombre de fonctionnalités d'un fichier à un autre fichier.
La plupart de ces opérations sont parallèlement d'une manière embarrassante en ce sens que les résultats des calculs n'influencent en aucune manière aucune autre opération dans la boucle. Non seulement cela, mais souvent les fichiers d'entrée sont chacun distincts.
Un exemple classique est la mise en mosaïque de fichiers de forme contre des fichiers contenant des polygones pour les couper.
Voici une méthode procédurale classique (testée) pour y parvenir dans un script python pour QGIS. (pour la sortie des fichiers de mémoire temporaire en fichiers réels, le temps de traitement de mes fichiers de test a été réduit de plus de moitié)
import processing
import os
input_file="/path/to/input_file.shp"
clip_polygons_file="/path/to/polygon_file.shp"
output_folder="/tmp/test/"
input_layer = QgsVectorLayer(input_file, "input file", "ogr")
QgsMapLayerRegistry.instance().addMapLayer(input_layer)
tile_layer = QgsVectorLayer(clip_polygons_file, "clip_polys", "ogr")
QgsMapLayerRegistry.instance().addMapLayer(tile_layer)
tile_layer_dp=input_layer.dataProvider()
EPSG_code=int(tile_layer_dp.crs().authid().split(":")[1])
tile_no=0
clipping_polygons = tile_layer.getFeatures()
for clipping_polygon in clipping_polygons:
print "Tile no: "+str(tile_no)
tile_no+=1
geom = clipping_polygon.geometry()
clip_layer=QgsVectorLayer("Polygon?crs=epsg:"+str(EPSG_code)+\
"&field=id:integer&index=yes","clip_polygon", "memory")
clip_layer_dp = clip_layer.dataProvider()
clip_layer.startEditing()
clip_layer_feature = QgsFeature()
clip_layer_feature.setGeometry(geom)
(res, outFeats) = clip_layer_dp.addFeatures([clip_layer_feature])
clip_layer.commitChanges()
clip_file = os.path.join(output_folder,"tile_"+str(tile_no)+".shp")
write_error = QgsVectorFileWriter.writeAsVectorFormat(clip_layer, \
clip_file, "system", \
QgsCoordinateReferenceSystem(EPSG_code), "ESRI Shapefile")
QgsMapLayerRegistry.instance().addMapLayer(clip_layer)
output_file = os.path.join(output_folder,str(tile_no)+".shp")
processing.runalg("qgis:clip", input_file, clip_file, output_file)
QgsMapLayerRegistry.instance().removeMapLayer(clip_layer.id())
Ce serait bien, sauf que mon fichier d'entrée est de 2 Go et que le fichier d'écrêtage de polygone contient plus de 400 polygones. Le processus résultant prend plus d'une semaine sur ma machine quadricœur. Pendant ce temps, trois cœurs tournent au ralenti.
La solution que j'ai dans ma tête est d'exporter le processus vers des fichiers de script et de les exécuter de manière asynchrone en utilisant gnu parallel par exemple. Cependant, il semble dommage de devoir abandonner QGIS dans une solution spécifique au système d'exploitation plutôt que d'utiliser quelque chose de natif pour QGIS python. Ma question est donc:
Puis-je paralléliser des opérations géographiques parallèlement embarrassantes en natif dans python QGIS?
Sinon, alors peut-être que quelqu'un a déjà le code pour envoyer ce genre de travail aux scripts shell asynchrones?
la source
Réponses:
Si vous changez votre programme pour lire le nom de fichier à partir de la ligne de commande et divisez votre fichier d'entrée en petits morceaux, vous pouvez faire quelque chose comme ça en utilisant GNU Parallel:
Cela exécutera 1 travail par cœur.
Tous les nouveaux ordinateurs ont plusieurs cœurs, mais la plupart des programmes sont de nature série et n'utiliseront donc pas les cœurs multiples. Cependant, de nombreuses tâches sont extrêmement parallélisables:
GNU Parallel est un paralléliseur général et permet d'exécuter facilement des travaux en parallèle sur la même machine ou sur plusieurs machines auxquelles vous avez accès ssh.
Si vous souhaitez exécuter 32 tâches différentes sur 4 processeurs, une manière simple de paralléliser consiste à exécuter 8 tâches sur chaque processeur:
Au lieu de cela, GNU Parallel engendre un nouveau processus une fois terminé - en gardant les CPU actifs et en économisant ainsi du temps:
Installation
Si GNU Parallel n'est pas empaqueté pour votre distribution, vous pouvez faire une installation personnelle, qui ne nécessite pas d'accès root. Cela peut être fait en 10 secondes en procédant comme suit:
Pour d'autres options d'installation, voir http://git.savannah.gnu.org/cgit/parallel.git/tree/README
Apprendre encore plus
Voir plus d'exemples: http://www.gnu.org/software/parallel/man.html
Regardez les vidéos d'introduction: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
Parcourez le didacticiel: http://www.gnu.org/software/parallel/parallel_tutorial.html
Inscrivez-vous à la liste de diffusion pour obtenir de l'aide: https://lists.gnu.org/mailman/listinfo/parallel
la source
my_processing.py
peut être trouvée sur gis.stackexchange.com/a/130337/26897Plutôt que d'utiliser la méthode GNU Parallel, vous pouvez utiliser le module python mutliprocess pour créer un pool de tâches et les exécuter. Je n'ai pas accès à une configuration QGIS pour le tester, mais le multiprocess a été ajouté en Python 2.6, à condition que vous utilisiez 2.6 ou une version ultérieure, il devrait être disponible. Il existe de nombreux exemples en ligne sur l'utilisation de ce module.
la source
Voici la solution parallèle GNU. Avec un peu de soin, les algorithmes ogr ou saga basés sur Linux les plus parallèles peuvent être exécutés avec lui dans votre installation QGIS.
Evidemment cette solution nécessite l'installation de gnu parallel. Pour installer gnu parallel dans Ubuntu, par exemple, allez sur votre terminal et tapez
NB: Je n'ai pas pu faire fonctionner la commande shell parallèle dans Popen ou sous-processus, ce que j'aurais préféré, j'ai donc piraté une exportation vers un script bash et l'ai exécutée avec Popen à la place.
Voici la commande shell spécifique utilisant le parallèle que j'ai enveloppé dans python
Chaque {1} est échangé contre un nombre de la plage {1..400}, puis les quatre cents commandes shell sont gérées par gnu parallèlement pour utiliser simultanément tous les cœurs de mon i7 :).
Voici le code python réel que j'ai écrit pour résoudre l'exemple de problème que j'ai publié. On pourrait le coller directement après la fin du code dans la question.
Permettez-moi de vous dire que c'est vraiment quelque chose quand vous voyez tous les cœurs se déclencher à plein bruit :). Un merci spécial à Ole et à l'équipe qui a construit Gnu Parallel.
Ce serait bien d'avoir une solution multiplateforme et ce serait bien si j'avais pu comprendre le module python multiprocesseur pour le python intégré qgis mais hélas ça ne devait pas l'être.
Peu importe cette solution me servira et peut-être bien.
la source