Moyens d'accélérer les scripts Python s'exécutant en tant qu'outils ArcGIS [fermé]

31

C'est une question assez générale. Je me demande simplement quels trucs et astuces les programmeurs SIG ont utilisés pour accélérer les scripts arcpy que vous importez dans la boîte à outils et exécutez.

La plupart du temps, j'écris de petits scripts pour aider les utilisateurs non SIG de mon bureau à traiter les données SIG. J'ai constaté que le traitement ArcGIS 10.0 en général est plus lent que 9.3.1 et parfois il devient encore plus lent lors de l'exécution d'un script python.

Je vais énumérer un exemple particulier d'un script qui prend plus de 24 heures pour s'exécuter. Il s'agit d'une boucle qui tabule la zone d'un raster dans un tampon pour chaque forme du tampon. Le tampon a environ 7 000 formes. Je ne pense pas que cela devrait durer aussi longtemps. UNE

while x <= layerRecords:

    arcpy.SetProgressorLabel("Tabulating Row: " + str(x) + " of " + str(ELClayerRecords))
    arcpy.SelectLayerByAttribute_management(Buff,"NEW_SELECTION", "Recno = " + str(x))                                  # Selecting the record
    TabulateArea(Buff, "Recno", MatGRID, "VALUE", ScratchWS + "/tab" + str(z) +".dbf", nMatGRIDc)                          # Tabulate the area of the single row

    arcpy.AddMessage ("          - Row: " + str(x) + " completed")
    x = x + 1
    z = z + 1

Avant que quelqu'un ne le dise, j'ai exécuté une zone de tabulation sur tout le tampon, mais cela produit des erreurs s'il est exécuté sur plus d'un enregistrement. C'est un outil imparfait, mais je dois l'utiliser.

Quoi qu'il en soit, si quelqu'un a des idées sur la façon d'optimiser ou d'accélérer ce script, ce serait très apprécié. Sinon, di vous avez des astuces pour accélérer python, lorsqu'il est utilisé dans ArcGIS?

Cody Brown
la source

Réponses:

26

Voici quelques suggestions potentielles pour accélérer votre processus:

  1. Sélectionner la couche par attribut peut être dans un script Python uniquement, sans jamais lancer ArcGIS Desktop. Vous devez convertir votre référence "buff" d'une référence basée sur un fichier en une référence "ArcGIS layer", sur laquelle ArcGIS peut traiter les requêtes de sélection. Utilisez arcpy.MakeFeatureLayer_management ("buff", "buff_lyr") au-dessus de votre boucle "while", puis modifiez vos références sous la boucle while pour utiliser "buff_lyr".

  2. Traitez autant d'opérations GP que possible en utilisant l' espace de travail in_memory ... Utilisez arcpy.CopyFeatures_management (shapefile, "in_memory \ memFeatureClass") pour déplacer votre source en mémoire. Cela ne fonctionne bien que si vous avez suffisamment de RAM pour lire toutes les classes d'entités dont vous avez besoin en mémoire. Attention, cependant, certaines opérations GP ne peuvent pas s'exécuter à l'aide de l'espace de travail in_memory (par exemple: l'outil Projet).

Dans l'article d'aide en ligne d'ArcGIS 9.3 « Données intermédiaires et espace de travail temporaire » (notez que cette langue a été supprimée de l'aide 10.0 et 10.1):

REMARQUE: seules les tables et les classes d'entités (points, lignes, polygones) peuvent être écrites dans l'espace de travail in_memory. L'espace de travail in_memory ne prend pas en charge les éléments de géodatabase étendus tels que les sous-types, les domaines, les représentations, les topologies, les réseaux géométriques et les jeux de données réseau. Seules des fonctionnalités et des tableaux simples peuvent être écrits.

Dans l'article d'aide en ligne d'ArcGIS 10.1 « Utilisation de l'espace de travail en mémoire »:

Les considérations suivantes doivent être prises en compte pour écrire la sortie dans l'espace de travail en mémoire:

  • Les données écrites dans l'espace de travail en mémoire sont temporaires et seront supprimées à la fermeture de l'application.
  • Les tables, les classes d'entités et les rasters peuvent être écrits dans l'espace de travail en mémoire.
  • L'espace de travail en mémoire ne prend pas en charge les éléments de géodatabase étendus tels que les sous-types, les domaines, les représentations, les topologies, les réseaux géométriques et les jeux de données réseau.
  • Les jeux de données d'entités ou les dossiers ne peuvent pas être créés dans l'espace de travail en mémoire.
RyanDalton
la source
1
C'est fantastique! Je cherchais un moyen d'utiliser des sélections en dehors d'ArcMap mais, jusqu'à présent, j'avais échoué. En ce qui concerne ce problème, cela a en fait réduit mon temps par ligne à environ 20 secondes au lieu de 13 secondes. Mais, j'ai fait un autre travail rapide autour et fait le MakeFeatureLayer dans la boucle et il est descendu à 9 secondes. J'ai fait cela en créant une entité à partir de chaque forme plutôt qu'en tabulant à partir de la couche d'entités. J'aimerais encore le faire descendre si possible, mais c'est déjà un processus beaucoup plus rapide!
Cody Brown
Comme mentionné dans # 2, utilisez les CopyFeatures pour faire une copie de vos données source in_memory, puis créez votre feature_layer par rapport à la source in_memory. Bien que la copie initiale en mémoire puisse ajouter quelques secondes à l'avance, vous pouvez constater que le traitement de copyfeatures + tabulate_areas a un temps de traitement total plus rapide que votre modèle actuel.
RyanDalton
J'ai également essayé et il semble que cette solution rendrait le processus de boucle plus rapide, mais ce n'est pas le cas. La création de la couche d'entités dans la boucle donne environ 8 à 10 secondes par boucle, tandis que la création de la couche d'entités avant la boucle entraîne 11 à 14 secondes par boucle. Je ne sais pas trop pourquoi, car votre solution semble fonctionner plus rapidement. J'ai 8 Go de RAM, donc je doute que ce soit le problème.
Cody Brown
Copier également les entités dans in_memory avant la boucle, puis créer toujours la couche d'entités dans la boucle entraîne des performances légèrement plus rapides. Il reste à peu près 8 secondes par ligne pour chaque boucle. Ce qui fera chuter le temps total de traitement de 26 heures à 22.
Cody Brown
Après avoir ajouté vos idées, mon script s'est considérablement amélioré. Merci beaucoup pour la vôtre et pour l'aide de tout le monde!
Cody Brown
28

Les techniques générales d'optimisation de python peuvent vous faire gagner beaucoup de temps.

Une très bonne technique pour savoir où se trouvent les blocages dans votre script consiste à utiliser le module cProfile intégré:

from cProfile import run
run("code") # replace code with your code or function

Les tests à l'aide d'un petit échantillon de données vous permettront d'identifier les appels de fonction qui prennent le plus de temps.

Pointeurs généraux pour un code python plus rapide:

  • La compréhension des listes est généralement plus rapide que la boucle
  • Les générateurs produisent un élément à la fois au lieu de produire la liste entière à la fois
  • Utilisez xrange au lieu de range en python 2 (pas nécessaire en 3)
  • Les ensembles peuvent sortir des listes de préformes lorsqu'il s'agit de déterminer si un élément est présent dans l'ensemble mais sont généralement plus lents que les listes lorsqu'il s'agit d'itérer sur leur contenu Source
  • Les appels de fonction peuvent être coûteux pour les performances Source
  • Plus de conseils et de détails, consultez ici Conseils de performance Python et ici 10 Conseils et problèmes d'optimisation Python

En ce qui concerne votre script, je ne peux pas commenter les aspects ArcPy car je n'ai pas Arc installé sur cet ordinateur, mais vous voudrez peut-être essayer d'utiliser une boucle for au lieu d'une boucle while pour voir si cela améliore quelque chose. De même, x = x + 1 peut s'écrire x + = 1:

for record in layerRecords:
arcpy.SetProgressorLabel("Tabulating Row: " + str(x) + " of " + str(ELClayerRecords))
arcpy.SelectLayerByAttribute_management(Buff,"NEW_SELECTION", "Recno = " + str(x))                                  # Selecting the record
TabulateArea(Buff, "Recno", MatGRID, "VALUE", ScratchWS + "/tab" + str(z) +".dbf", nMatGRIDc)                          # Tabulate the area of the single row

arcpy.AddMessage ("          - Row: " + str(x) + " completed")
x+=1
y+=1
James Milner
la source
1
J'ai utilisé les deux liens que vous avez laissés sur votre dernière puce et j'ai vraiment pu aider mon script avec quelques correctifs rapides!
Cody Brown
Si je pouvais attribuer deux bonnes réponses, je le ferais. Alors que votre réponse offrait vraiment beaucoup d'idées sur la façon d'accélérer le python, @RyanDalton a proposé l'idée qui avait le plus d'impact. Merci beaucoup!
Cody Brown
13

Assurez-vous que vous écrivez sur le disque interne de l'ordinateur. Atteindre le réseau lorsque cela n'est pas nécessaire peut vraiment ralentir le traitement. Il peut même être plus rapide de copier les données comme première étape du processus pour que les lectures-écritures suivantes soient aussi rapides que possible.

L'exécution du script complètement en dehors d'ArcMap peut être beaucoup plus rapide. Si une carte n'est pas requise pendant le traitement, n'utilisez pas ArcMap.

mhoran_psprep
la source
J'ai constaté que l'exécution d'un script à l'intérieur d'un modèle à partir d'ArcCatalog (par lui-même à l'intérieur d'une Calculate Valueboîte de dialogue) sera plus rapide que l'exécution du même script à partir de la fenêtre ArcPy dans ArcMap. C'est une observation purement anecdotique.
Cindy Jayakumar
1
Je crois que j'ai besoin d'une carte pour que Tabulate fonctionne correctement, mais je vais essayer ceci. Si cela fonctionne en dehors d'ArcMap, je parie que cela accélérerait. De plus, je suis déjà en cours d'exécution sur le disque local, qui a déjà doublé la vitesse du script.
Cody Brown
Malheureusement, la sélection ne fonctionne pas en dehors d'ArcMap et elle est nécessaire car je dois faire le tableau forme par forme.
Cody Brown
3
@ CodyBrown - Vous avez tort de ne pas travailler en dehors d'une session ArcMap. Voir ma réponse sur l'utilisation de l'outil MakeFeatureLayer.
RyanDalton
Ryan a raison. Lorsque l'outil de sélection est utilisé seul, il crée une vue tabulaire de vos données spatiales ou de vos données de table. Lorsque vous l'utilisez dans ModelBuilde ou dans un script, vous devez créer une vue et, dans votre cas, la créer à l'aide de l'outil MakeFeatureLayer.
dchaboya
6

Cela ne répond peut-être pas à votre question concernant l'exécution des outils ArcPy dans ArcMap, mais lorsque j'ai besoin d'effectuer un traitement charnu avec des outils de géotraitement et Python, j'ai tendance à l'exécuter en dehors du système SIG à l'aide de l'IDE PyScripter . J'ai trouvé qu'il fonctionne plus rapidement. J'ai également utilisé un RAMDISK pour les petits jeux de données de sortie temporaires (un peu comme l' espace de travail in_memory )

Eh bien, ce sont mes meilleurs conseils! :)

Hornbydd
la source
2
Pour brouiller quelque peu cette réponse, lors de l'exécution de scripts à partir d'IDE Python, beaucoup injectent une fonction de traceback pour aider à surveiller les variables et d'autres aides au débogage. Cette fonction peut ralentir massivement les scripts si elle en fait trop car elle est appelée TOUT LE TEMPS, et parfois elle est installée implicitement sans intervention de l'utilisateur. Il y a eu un cas pathologique particulier que j'ai observé où un script Python exécuté dans ArcMap a fonctionné en 4 minutes, tandis que le même script de Wing IDE a pris 3 heures. Dès qu'il a été exécuté à partir de Python.exe sans Wing, il est revenu à environ 2-3 minutes d'exécution.
Jason Scheirer
1
j'avais des maux de tête pour régler mes scripts sur ArMap, parfois je ne peux pas complètement, jusqu'à ce que je me tourne vers Pyscripter, cela peut réduire le temps d'exécution par rapport à Arcmap, sans utiliser aucune astuce d'optimisation.
geogeek
@JasonScheirer avez-vous trouvé le tweak dans Wing pour désactiver cela? Je suis sûr qu'il y en a un.
Curtis Price
5

Essayez de commenter arcpy.SetProgressorLabel et voyez combien vous accélérez. J'ai trouvé que toute sortie d'écran, en revenant à DOS Daze, ralentit considérablement les temps de traitement. Si vous avez vraiment besoin de voir cette sortie, essayez de l'afficher à chaque Nième boucle.

user30749
la source
4

Assurez-vous de supprimer toutes les import xxxxlignes qui ne sont pas utilisées.

(c.-à-d. si vous n'utilisez pas encore de fonctions mathématiques, vous en import Mathaurez pour le chargement du script)

Bien que cela n'ait pas un grand impact sur les scripts uniques qui s'exécutent (comme le vôtre), cela affectera tous les scripts qui s'exécutent fréquemment et de manière répétitive.

nagytech
la source
7
Je doute qu'un module Python standard prenne plus d'un millième du temps qu'il faut au module arcpy pour s'initialiser.
blah238
1
@ blah238 import Mathétait probablement un mauvais exemple. Cependant, certaines des plus grandes bibliothèques ArcPy prennent beaucoup de temps à charger.
nagytech
1
cela ne coupe que quelques secondes (tout au plus!), pas des heures
Mike T
1
@MikeToews Pour les scripts qui s'exécutent fréquemment et de manière répétitive, quelques secondes s'additionnent au cours de quelques jours / semaines, etc. Bien que cela ne résout pas le problème principal du PO, il a demandé des conseils généraux.
nagytech