Suite

Maximiser l'utilisation du processeur


Mon script croise des lignes avec des polygones. C'est un long processus puisqu'il y a plus de 3000 lignes et plus de 500000 polygones. J'ai exécuté à partir de PyScripter :

# Import import arcpy import time # Définir l'environnement arcpy.env.workspace = r"E:DensityMapsDensityMapsTest1.gdb" arcpy.env.overwriteOutput = True # Définir la minuterie à partir de datetime import datetime startTime = datetime.now() # Définir local variables inFeatures = [r"E:DensityMapsDensityMapsTest.gdbGrid1km_Clip", "JanuaryLines2"] outFeatures = "JanuaryLinesIntersect" outType = "LINE" # Faire des lignes arcpy.Intersect_analysis(inFeatures, outFeatures, "", "", outType ) #Print end time print "Terminé "+str(datetime.now() - startTime)


Ma question est : existe-t-il un moyen de faire fonctionner le processeur à 100% ? Il tourne à 25% tout le temps. Je suppose que le script s'exécuterait plus rapidement si le processeur était à 100%. Mauvaise supposition ?
Ma machine est :

  • Norme Windows Server 2012 R2
  • Processeur : Intel Xeon CPU E5-2630 0 @2,30 GHz 2,29 GHz
  • Mémoire installée : 31,6 Go
  • Type de système : système d'exploitation 64 bits, processeur x64


Laissez-moi deviner : votre processeur a 4 cœurs, donc 25 % d'utilisation du processeur correspond à 100 % d'utilisation d'un cœur et de 3 cœurs inactifs.

La seule solution est donc de rendre le code multi-thread, mais ce n'est pas une tâche simple.


Je ne suis pas sûr qu'il s'agisse d'une tâche liée au processeur. Je pense que ce serait une opération liée aux E/S, donc je chercherais à utiliser le disque le plus rapide auquel j'aurais accès.

Si E: est un lecteur réseau, l'éliminer serait la première étape. S'il ne s'agit pas d'un disque hautes performances (recherche <7 ms), ce serait le deuxième. Vous pouvez obtenir certains avantages en copiant la couche de polygones dans unen mémoireespace de travail, mais l'avantage peut dépendre de la taille de la classe d'entités surfaciques et de l'utilisation ou non d'un traitement en arrière-plan 64 bits.

L'optimisation du débit d'E/S est souvent la clé des performances SIG, je vous recommande donc de porter moins d'attention au compteur CPU et plus d'attention aux compteurs réseau et disque.


J'ai eu des problèmes de performances similaires concernant les scripts arcpy, le principal goulot d'étranglement n'est pas le CPU sur le disque dur, si vous utilisez des données du réseau c'est le pire des scénarios, essayez de déplacer vos données vers le lecteur SSD, puis lancez votre script depuis la ligne de commande pas de pyscripter , pyscripter est légèrement plus lent peut-être parce qu'il contient des trucs de débogage, si vous n'êtes pas satisfait à nouveau, pensez à mettre en parallèle votre script, car chaque thread python prend un cœur de processeur, votre processeur a 6 cœurs, vous pouvez donc lancer 6 scripts simultanément.


Comme vous utilisez python et comme suggéré ci-dessus, envisagez d'utiliser le multitraitement si votre problème peut être exécuté en parallèle.

J'ai écrit un petit article sur le site web de geonet sur la conversion d'un script python en un outil de script python qui pourrait être utilisé dans modelbuilder. Le document répertorie le code et décrit certains pièges pour l'exécuter en tant qu'outil de script. Ce n'est qu'un endroit pour commencer à chercher :

https://geonet.esri.com/docs/DOC-3824


Comme dit précédemment, vous devez utiliser le multitraitement ou le threading. Mais voici la mise en garde : le problème doit être divisible ! Alors jetez un œil à https://en.wikipedia.org/wiki/Divide_and_conquer_algorithms.

Si votre problème est divisible, procédez comme suit :

  • Créez une file d'attente dans laquelle vous stockez les données d'entrée pour les processus/thread
  • Créer une file d'attente dans laquelle les résultats sont stockés
  • Créer une fonction ou une classe qui peut être utilisée comme processus/thread qui résout notre problème

Mais comme l'a dit geogeek, ce n'est peut-être pas un problème de limitation du processeur, mais un problème d'E/S. Si vous disposez de suffisamment de RAM, vous pouvez pré-charger toutes les données puis les traiter, ce qui présente l'avantage que les données peuvent être lues en une seule fois et n'interrompent donc pas toujours le processus de calcul.


J'ai décidé de le tester en utilisant 21513 lignes et 498596 polygones. J'ai testé l'approche multiprocesseur (12 processeurs sur ma machine) en utilisant ce script :

import arcpy,os import multiprocessing import time t0 = time.time() arcpy.env.overwriteOutput = True nProcessors=4 folder=r'd:scratch' def function(inputs): nGroup=inputs[0] pGons=inputs[ 1] lines=inputs[2] outFeatures = '%s%s%s_%i.shp' %(folder,os.sep,'inters',nGroup) fids= tuple([i for i in range(nGroup,500000 ,nProcessors-1)]) lyr="layer%s"%nGroupFID" in %s" %str(fids) arcpy.MakeFeatureLayer_management(pGons,lyr,query) arcpy.Intersect_analysis([lines,lyr], outFeatures) return outFeatures if __name__ == "__main__": inPgons="%s%s%s" %(dossier,os.sep,'parcels.shp') inLines="%s%s%s" %(dossier,os.sep, 'roads.shp') m,bList=0,[] for i in range(nProcessors): bList.append([i,inPgons,inLines]) pool = multiprocessing.Pool(nProcessors-1) listik=pool.map( function, bList) ## appliquer la fusion ici print listik print ('%i seconds' %(time.time()-t0))

Résultats, secondes :

  • disque dur local normal - 191
  • lecteur local ultra-rapide - 220
  • lecteur réseau - 252

La chose amusante, cela n'a pris que 87 secondes en utilisant l'outil de géotraitement de mxd. Peut-être que quelque chose ne va pas dans mon approche de la piscine…

Comme on peut le voir, j'ai utilisé une requête FID plutôt moche dans (0, 4, 8,12… 500000) pour rendre la tâche divisible.

Il est possible que la requête basée sur un champ pré-calculé, par ex. CFIELD=0 réduira considérablement le temps.

J'ai également constaté que le temps rapporté par les outils de multitraitement peut varier considérablement.


Je ne connais pas PyScripter, mais s'il est soutenu par CPython, vous devriez opter pour le multitraitement et non le multithreading tant que le problème lui-même est divisible (comme d'autres l'ont déjà mentionné).

CPython a un Global Interpreter Lock, qui annule tous les avantages que plusieurs threads pourraient apporter ton cas.

Bien sûr, dans d'autres contextes, les threads python sont utiles, mais pas dans les cas où vous êtes lié au processeur.


Ma question est : y a-t-il un moyen de faire fonctionner le processeur à 100%

Comme votre processeur a plusieurs cœurs, vous ne maximiserez que le cœur sur lequel votre processus s'exécute. Selon la configuration de votre puce Xeon, elle fonctionnera jusqu'à 12 cœurs (6 physiques et 6 virtuels avec hyperthreading activé). Même ArcGIS 64 bits n'est pas vraiment en mesure de tirer parti de cela - et cela peut entraîner des limitations du processeur lorsque votre processus à thread unique maximise le cœur sur lequel il s'exécute. Vous avez besoin d'une application multithread pour répartir la charge sur les cœurs OU (beaucoup plus simplement) vous pouvez réduire le nombre de cœurs exécutés par votre processeur pour augmenter le débit.

Le moyen le plus simple d'arrêter la limitation du processeur (et de vous assurer qu'il s'agit bien d'une limitation de processeur et non de restrictions d'E/S de disque) est de modifier les paramètres du BIOS de votre Xeon et de le définir sur un seul cœur massif. L'augmentation des performances sera substantielle. N'oubliez pas que cela compromet également considérablement la capacité multitâche de votre PC, il est donc préférable que vous disposiez d'une machine de traitement dédiée pour l'implémenter. C'est beaucoup plus simple que d'essayer de multi-threader votre code - que la plupart des fonctions d'ArcGIS Desktop (comme à 10.3.1) ne prennent pas en charge de toute façon.