Vale a pena usar processos paralelos em vez de forjar em um loop for?

2

O seguinte loop for executa milhares de trabalhos em paralelo

OSMSOURCE=europe-latest.o5m
for SHAPEFILE in URBAN_[A-Z]*[0-9] ;do
    cd $SHAPEFILE
    for POLYGON in *.poly ;do
        osmconvert --drop-version $OSMSOURCE -B=$POLYGON --out-o5m > $(basename $OSMSOURCE .o5m |tr "-" "_")_$(basename $POLYGON .poly).o5m &
    done
    cd ..
done

Eu quero aprender como o GNU paralelo executa e entender se vale a pena usar.

    
por Nikos Alexandris 17.08.2017 / 10:20

4 respostas

2

Bem, o GNU paralelo fará o mesmo e é fácil de usar. Sua vantagem é que ele cuidará do número de núcleos de CPU em sua máquina e, por padrão, não executará mais trabalhos do que isso (*).

Seu programa não. Se você tiver centenas de arquivos .poly , gerará centenas de trabalhos osmconvert , o que na melhor das hipóteses pode não ser o melhor possível e, na pior das hipóteses, pode colocar seu sistema inativo (depende de seus recursos).

Seu programa seria algo como (não testado):

OSMSOURCE=europe-latest.o5m
OSMBASENAME="$(echo "${OSMSOURCE%.o5m}" | tr - _)"

for SHAPEFILE in URBAN_[A-Z]*[0-9]; do
    cd "$SHAPEFILE"
    for POLYGON in *.poly; do
        echo "cd '$SHAPEFILE'; osmconvert --drop-version '$OSMSOURCE' -B='$POLYGON' --out-o5m > '${OSMBASENAME}_${POLYGON%.poly}.o5m'"
    done
    cd ..
done | parallel        # You may want to add a -j option

(*) Você pode dar seu próprio limite. Você pode querer manter alguns núcleos extras de CPU para outra coisa. Por outro lado, se E / S é o gargalo, você pode querer dar um número maior do que o padrão.

    
por 17.08.2017 / 10:32
1

Provavelmente você pode fazer algo como:

OSMSOURCE=europe-latest.o5m
export OSMSOURCE

doit() {
  cd "$1"
  POLYGON="$2"
  osmconvert --drop-version $OSMSOURCE -B=$POLYGON --out-o5m > $(basename $OSMSOURCE .o5m |tr "-" "_")_$(basename $POLYGON .poly).o5m
}
export -f doit

Agora você pode testar se isso funciona manualmente:

doit URBAN_dir file_in_URBAN_dir.poly

Quando isso funciona:

parallel doit {//} {/} ::: URBAN_[A-Z]*[0-9]/*.poly

Se isso der a command too long , tente:

find URBAN_[A-Z]*[0-9] -name *.poly | parallel doit {//} {/}

Ou:

find . | grep -E 'URBAN_[A-Z].*[0-9]/.*.poly$' | parallel doit {//} {/}

Gaste uma hora percorrendo man parallel_tutorial . Sua linha de comando vai agradecer por isso.

    
por 17.08.2017 / 16:55
0

Testes de tempo das conversões com base nas respostas disponíveis e um pequeno conjunto de dados.

Conjunto de dados de teste

Diretórios do Shapefiles da ESRI

URAU_RG_100K_2011_2014_AT001L2
URAU_RG_100K_2011_2014_AT002L2
URAU_RG_100K_2011_2014_AT003L2
URAU_RG_100K_2011_2014_AT004L2
URAU_RG_100K_2011_2014_AT005L2
URAU_RG_100K_2011_2014_AT006L1
URAU_RG_100K_2011_2014_UK546L0

que inclui os seguintes 9 arquivos .poly

URAU_RG_100K_2011_2014_AT001L2/URAU_RG_100K_2011_2014_AT001L2_0.poly
URAU_RG_100K_2011_2014_AT002L2/URAU_RG_100K_2011_2014_AT002L2_0.poly
URAU_RG_100K_2011_2014_AT003L2/URAU_RG_100K_2011_2014_AT003L2_0.poly
URAU_RG_100K_2011_2014_AT004L2/URAU_RG_100K_2011_2014_AT004L2_0.poly
URAU_RG_100K_2011_2014_AT005L2/URAU_RG_100K_2011_2014_AT005L2_0.poly
URAU_RG_100K_2011_2014_AT006L1/URAU_RG_100K_2011_2014_AT006L1_0.poly
URAU_RG_100K_2011_2014_UK546L0/URAU_RG_100K_2011_2014_UK546L0_0.poly
URAU_RG_100K_2011_2014_UK546L0/URAU_RG_100K_2011_2014_UK546L0_1.poly
URAU_RG_100K_2011_2014_UK546L0/URAU_RG_100K_2011_2014_UK546L0_2.poly

vai lançar 9 trabalhos em paralelo

Bifurcação

for SHAPEFILE in URAU_RG_100K_2011_2014_[A-Z]*[0-9]/ ;do cd $SHAPEFILE && for POLYGON in *.poly ;do time osmconvert --drop-version $OSMSOURCE -B=$POLYGON --out-o5m > $(basename $OSMSOURCE .o5m |tr "-" "_")_$(basename $POLYGON .poly).o5m & done && cd .. ;done
real    6m0.951s
user    5m36.869s
sys     0m20.298s

real    6m23.591s
user    5m43.808s
sys     0m20.336s

real    6m24.066s
user    5m44.619s
sys     0m19.936s

real    6m24.129s
user    5m45.239s
sys     0m19.378s

real    6m29.208s
user    5m43.094s
sys     0m19.314s

real    6m30.974s
user    5m44.318s
sys     0m19.870s

real    6m33.625s
user    5m45.233s
sys     0m19.658s

real    6m33.731s
user    5m45.712s
sys     0m20.001s

real    6m41.014s
user    6m15.112s
sys     0m19.571s

Paralelo GNU

for SHAPEFILE in URAU_RG_100K_2011_2014_[A-Z]*[0-9]*/ ;do cd "$SHAPEFILE"; for POLYGON in *.poly ;do echo "cd '$SHAPEFILE'; time osmconvert --drop-version '$OSMSOURCE' -B='$POLYGON' --out-o5m > $(basename $OSMSOURCE .o5m |tr "-" "_")_$(basename $POLYGON .poly).o5m"; done; cd ..; done |parallel -j 10
real    6m19.005s
user    5m42.739s
sys     0m18.798s

real    6m26.939s
user    5m44.689s
sys     0m19.257s

real    6m27.152s
user    5m44.597s
sys     0m19.644s

real    6m28.821s
user    5m41.650s
sys     0m18.283s

real    6m38.174s
user    5m44.367s
sys     0m19.564s

real    6m40.277s
user    5m45.000s
sys     0m19.650s

real    6m39.940s
user    5m45.421s
sys     0m19.208s

real    6m40.285s
user    5m45.443s
sys     0m19.393s

real    6m40.428s
user    5m48.828s
sys     0m18.871s

Usando nomes absolutos de caminho e arquivo

for SHAPEFILE in URAU_RG_100K_2011_2014_[A-Z]*[0-9]*/ ;do for POLYGON in $SHAPEFILE*.poly ;do echo "time osmconvert --drop-version --out-o5m $OSMSOURCE -B=$(readlink -f $POLYGON) > $(dirname 'readlink -f $POLYGON')/$(basename ${OSMSOURCE%.o5m})_$(basename ${POLYGON%.poly}).o5m" ;done ;done |parallel -j 10
real    6m6.919s
user    5m39.203s
sys     0m19.659s

real    6m23.779s
user    5m43.835s
sys     0m19.225s

real    6m26.033s
user    5m45.370s
sys     0m19.235s

real    6m26.871s
user    5m46.124s
sys     0m19.780s

real    6m33.355s
user    5m41.902s
sys     0m18.556s

real    6m34.368s
user    5m42.973s
sys     0m19.156s

real    6m37.063s
user    5m46.169s
sys     0m19.669s

real    6m37.363s
user    5m46.846s
sys     0m19.194s

real    6m37.428s
user    5m49.679s
sys     0m19.674s

Definindo uma função de shell

OSMSOURCE=$(realpath europe-latest.o5m)
export OSMSOURCE

osmpolyclip() {
    cd "$1"
    POLYGON="$2"
    osmconvert --drop-version $OSMSOURCE -B=$POLYGON --out-o5m > $(basename $OSMSOURCE .o5m |tr "-" "_")_$(basename $POLYGON .poly).o5m
}

e

parallel time osmpolyclip {//} {/} ::: URAU_[A-Z]*[0-9]/*.poly
real    6m19.749s
user    5m41.909s
sys     0m19.162s

real    6m23.559s
user    5m43.881s
sys     0m18.748s

real    6m34.149s
user    5m41.859s
sys     0m18.895s

real    6m38.776s
user    5m44.614s
sys     0m18.767s

real    6m38.817s
user    5m44.420s
sys     0m19.038s

real    6m39.421s
user    5m46.060s
sys     0m18.819s

real    6m39.889s
user    5m45.917s
sys     0m19.541s

real    6m39.956s
user    5m48.368s
sys     0m19.742s

real    6m51.397s
user    6m26.095s
sys     0m19.306s

No entanto, esse é um conjunto de testes mínimo, comparado aos milhares de arquivos Polygon a serem solicitados para conversão. Além disso, os arquivos residem em um diretório remoto que efetivamente reduz a leitura e a escrita.

    
por 18.08.2017 / 16:01
0

Temporizações em um sistema de 80 núcleos

Usando nomes absolutos de caminho e arquivo,

for SHAPEFILE in URAU_RG_100K_2011_2014_[A-Z]*[0-9]*/ ;do for POLYGON in $SHAPEFILE*.poly ;do echo "time osmconvert --drop-version --out-o5m $OSMSOURCE -B=$(readlink -f $POLYGON) > $(dirname 'readlink -f $POLYGON')/$(basename ${OSMSOURCE%.o5m})_$(basename ${POLYGON%.poly}).o5m" ;done ;done |parallel -j 10

os tempos para 3559 conversões, em segundos, usando o GNU Parallel, são

 timings.real    timings.user    timings.sys

 Min.   :387.4   Min.   :367.5   Min.   :17.95
 1st Qu.:636.8   1st Qu.:616.3   1st Qu.:19.35
 Median :639.4   Median :618.5   Median :19.74
 Mean   :637.6   Mean   :616.8   Mean   :19.81
 3rd Qu.:642.5   3rd Qu.:621.5   3rd Qu.:20.15
 Max.   :709.3   Max.   :689.9   Max.   :27.34

Detalhes do sistema

Os processos foram executados de dentro de um Ubuntu 16.04.2 LTS dockerised (veja link ), enquanto o host é uma caixa do CentOS (Linux 3.10.0-514.26.2.el7.x86_64 # 1 SMP). A memória total é 1056760752 kB e o número de processadores Intel (R) Xeon® E7-4820 v3 @ 1.90GHz são 80.

    
por 04.09.2017 / 15:47