Maximiser l'utilisation du CPU

9

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

# Import
import arcpy
import time

# Set envvironment
arcpy.env.workspace = r"E:\DensityMaps\DensityMapsTest1.gdb"
arcpy.env.overwriteOutput = True

# Set timer
from datetime import datetime
startTime = datetime.now()

# Set local variables
inFeatures = [r"E:\DensityMaps\DensityMapsTest.gdb\Grid1km_Clip", "JanuaryLines2"]
outFeatures = "JanuaryLinesIntersect"
outType = "LINE"

# Make lines
arcpy.Intersect_analysis(inFeatures, outFeatures, "", "", outType)

#Print end time
print "Finished "+str(datetime.now() - startTime)


Ma question est: existe-t-il un moyen de faire fonctionner le CPU à 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:

  • Windows Server 2012 R2 Standard
  • 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


entrez la description de l'image ici

Manuel Frias
la source
Je suggère fortement d'opter pour le multi-threading. Ce n'est pas anodin à mettre en place mais cela fera plus que compenser les efforts.
alok jha
1
Quel type d'index spatial avez-vous appliqué à vos polygones?
Kirk Kuykendall,
1
Avez-vous également essayé la même opération avec ArcGIS Pro? Il est en 64 bits et prend en charge le multithread. Je serais surpris si c'est assez intelligent pour diviser une intersection en plusieurs threads, mais ça vaut le coup d'essayer.
Kirk Kuykendall,
La classe d'entités surfaciques a un index spatial nommé FDO_Shape. Je n'y ai pas pensé. Dois-je en créer un autre? N'est-ce pas suffisant?
Manuel Frias
1
Puisque vous avez beaucoup de RAM ... avez-vous essayé de copier les polygones dans une classe de caractéristiques en mémoire, puis d'intersecter les lignes avec cela? Ou si vous le gardiez sur le disque, avez-vous essayé de le compacter? Le compactage est censé améliorer les E / S.
Kirk Kuykendall

Réponses:

13

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

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

MTilsted
la source
4
Le CPU qu'il mentionne utilise 6 cœurs et 12 threads.
Kersten
5
Salut, je ne peux pas downvote mais j'aimerais bien! Python a un GIL malheureusement, donc vous ne pouvez pas du tout multithread (le mieux que vous puissiez faire est de déverrouiller le GIL lorsqu'un thread bloque sur un syscall)
Alec Teal
2
@AlecTeal vous pouvez certainement, par exemple avec Jython ou le multiprocessingmodule.
droite le
@elyse va "Oh oui, vous pouvez totalement le faire en Python, si par Python vous voulez dire Jython" ne compte pas. Je devrais me pencher sur le multitraitement, une importation aurait-elle le pouvoir de réimplémenter ce qui fait Python Python?
Alec Teal
@AlecTeal Il génère des processus (qui sont une façon de faire du parallélisme). Voir la documentation du multiprocessingmodule.
plié à droite le
13

Je ne suis pas sûr que ce soit 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 eu accès.

Si E: est un lecteur réseau, l'élimination de ce serait la première étape. S'il ne s'agit pas d'un disque haute performance (<7 ms de recherche), ce serait le deuxième. Vous pouvez obtenir un certain avantage en copiant la couche de polygones dans un in_memoryespace de travail, mais l'avantage peut dépendre de la taille de la classe d'entités surfaciques et de votre utilisation du traitement d'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 prêter moins d'attention au compteur CPU et plus d'attention au réseau et aux compteurs de disque.

Vince
la source
4

J'ai eu des problèmes de performances similaires en ce qui concerne les scripts arcpy, le principal goulot d'étranglement n'est pas le CPU, c'est le disque dur, si vous utilisez des données du réseau qui est le pire scénario, essayez de déplacer vos données sur le disque SSD, puis lancez votre script à partir de 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 coeur de CPU, votre CPU a 6 cœurs, donc vous pouvez lancer 6 scripts simultanément.

geogeek
la source
3

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

Hornbydd
la source
Cela semble être la voie à suivre! Votre script fonctionne bien mais je ne sais pas comment le modifier pour le faire fonctionner avec mon script. Mieux, je pensais faire une intersection tabulaire avec des polygones et des lignes. Une idée?
Manuel Frias
3

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

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

  • Créez une file d'attente où vous stockez les données d'entrée pour les processus / thread
  • Créer une file d'attente où les résultats sont stockés dans
  • Créez une fonction ou une classe qui peut être utilisée comme un 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 avez suffisamment de RAM, vous pouvez pré-charger toutes les données puis les traiter, ce qui a l'avantage que les données peuvent être lues en une seule fois, ce qui n'interrompt pas toujours le processus de calcul.

Benjamin
la source
3

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'%nGroup
        query='"FID" 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' %(folder,os.sep,'parcels.shp')
        inLines='%s%s%s' %(folder,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)
##      apply merge here
        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, il n'a fallu que 87 secondes en utilisant l'outil de géotraitement de mxd. Peut-être quelque chose de mal avec mon approche de la piscine ...

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

Il est possible qu'une requête basée sur un champ pré-calculé, par exemple CFIELD = 0, réduise considérablement le temps.

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

FelixIP
la source
1
Oui, vous utilisez une liste, qui s'accompagne de problèmes de verrouillage. Essayez un fichier multiprocessing.queue. Essayez également de ne pas écrire de trucs dans les processus de travail, mais créez une file d'attente de sortie avec les données que vous souhaitez écrire et laissez-le faire par un processus d'écriture.
Benjamin
3

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

CPython dispose d'un verrou d'interpréteur global , qui annule tous les avantages que plusieurs threads pourraient apporter à votre cas .

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

user1514631
la source
1

Ma question est: existe-t-il un moyen de faire fonctionner le CPU à 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 que votre processeur exécute pour augmenter le débit.

La façon la plus simple d'arrêter la limitation du processeur (et de vous assurer qu'il s'agit bien d'une limitation du processeur et non de restrictions d'E / S 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 réduit considérablement la capacité de multitâche de votre PC, il est donc préférable que vous ayez une machine de traitement dédiée pour la mettre en œuvre. C'est beaucoup plus simple que d'essayer de multi-thread votre code - que la plupart des fonctions ArcGIS Desktop (comme à la 10.3.1) ne prennent pas en charge de toute façon.

kingmi
la source
Quel paramètre devez-vous rechercher pour transformer votre processeur en "un seul cœur massif"?
Alex McVittie
1
Le menu exact dépendra de votre BIOS et du micrologiciel de la puce, mais il se trouvera généralement dans le menu BIOS Setup> Advanced> CPU Configuration. Vous souhaiterez désactiver l'hyper-threading, puis définir le nombre de cœurs à activer. 0 est généralement réglé sur 1 si vous voulez un gros noyau. Bonne idée de prendre note des paramètres avant de changer les choses - cela semble évident mais facile à ignorer si les choses ne fonctionnent pas.
kingmi