PyQGIS에서 GIS 운영을 병렬화합니까?


15

GIS의 일반적인 요구 사항은 처리 도구를 여러 파일에 적용하거나 한 파일의 여러 기능에 대한 프로세스를 다른 파일에 적용하는 것입니다.

이러한 연산의 대부분은 계산 결과가 루프의 다른 연산에 영향을 미치지 않는다는 점에서 당혹스럽게 평행합니다. 뿐만 아니라 종종 입력 파일이 서로 다릅니다.

전형적인 예는 다각형을 포함하는 파일에 대해 모양 파일을 바둑판 식으로 배열하는 것입니다.

다음은 QGIS 용 파이썬 스크립트에서이를 달성하기위한 (테스트 된) 고전적인 절차 적 방법입니다. (임시 메모리 파일의 출력을 실제 파일로 출력하여 테스트 파일 처리 시간을 절반 이상 줄였습니다)

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())

입력 파일이 2GB이고 다각형 클리핑 파일에 400 개 이상의 다각형이 포함되어있는 것을 제외하고는 괜찮을 것입니다. 결과 프로세스는 쿼드 코어 시스템에서 일주일 이상 걸립니다. 모든 3 개의 코어는 공전 상태입니다.

내 머리 속에있는 해결책은 프로세스를 스크립트 파일로 내보내고 예를 들어 gnu parallel을 사용하여 비동기 적으로 실행하는 것입니다. 그러나 QGIS python 고유의 것을 사용하는 대신 QGIS에서 OS 특정 솔루션으로 빠져 나가는 것이 부끄러운 것 같습니다. 그래서 내 질문은 :

파이썬 QGIS 내부에서 당황스럽게 병렬 지리 작업을 병렬화 할 수 있습니까?

그렇지 않다면 누군가 이런 종류의 작업을 비동기 쉘 스크립트로 보내는 코드가 이미 있습니까?


QGIS의 멀티 프로세싱에 익숙하지 않지만이 ArcGIS 관련 예제는 유용 할 수 있습니다. gis.stackexchange.com/a/20352/753
blah238

재미있어 보인다. 내가 할 수있는 일을 볼 수 있습니다.
Mr Purple

답변:


11

명령 행에서 파일 이름을 읽도록 프로그램을 변경하고 입력 파일을 더 작은 청크로 분할하면 GNU Parallel을 사용하여 다음과 같이 할 수 있습니다.

parallel my_processing.py {} /path/to/polygon_file.shp ::: input_files*.shp

코어 당 1 개의 작업이 실행됩니다.

모든 새 컴퓨터에는 여러 개의 코어가 있지만 대부분의 프로그램은 본질적으로 직렬이므로 여러 개의 코어를 사용하지 않습니다. 그러나 많은 작업을 매우 병렬화 할 수 있습니다.

  • 많은 파일에서 같은 프로그램을 실행
  • 파일의 모든 줄에 대해 동일한 프로그램을 실행하십시오.
  • 파일의 모든 블록에 대해 동일한 프로그램을 실행하십시오.

GNU Parallel은 일반적인 병렬 처리기이므로 동일한 컴퓨터 또는 ssh 액세스 권한이있는 여러 컴퓨터에서 작업을 병렬로 쉽게 실행할 수 있습니다.

4 개의 CPU에서 32 개의 서로 다른 작업을 실행하려는 경우 병렬화하는 간단한 방법은 각 CPU에서 8 개의 작업을 실행하는 것입니다.

간단한 예약

대신 GNU Parallel은 프로세스가 완료되면 새로운 프로세스를 생성하여 CPU를 활성화하여 시간을 절약합니다.

GNU 병렬 스케줄링

설치

GNU Parallel이 배포 용으로 패키지되어 있지 않은 경우 루트 액세스가 필요없는 개인 설치를 수행 할 수 있습니다. 다음을 수행하여 10 초 안에 완료 할 수 있습니다.

(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash

다른 설치 옵션은 http://git.savannah.gnu.org/cgit/parallel.git/tree/README를 참조하십시오.

더 알아보기

더 많은 예를보십시오 : http://www.gnu.org/software/parallel/man.html

소개 동영상 시청 : https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

다음 자습서를 진행하십시오. http://www.gnu.org/software/parallel/parallel_tutorial.html

지원을 받으려면 이메일 목록에 가입 하십시오 : https://lists.gnu.org/mailman/listinfo/parallel


이것은 내가 시도하고 시도하는 것과 같지만 파이썬 안에 남아 있어야합니다. 라인은 Popen을 사용하기 위해 재 작성이 필요합니다. 예를 들면 다음과 같습니다. .shp "input.shp"], stdin = PIPE, stdout = PIPE, stderr = PIPE) 문제는 아직 구문을 올바르게 준비하는 방법을 모르는 것입니다
Mr Purple

멋진 답변입니다. 전에는 트리플 (또는 쿼드) 콜론 연산자를 본 적이 없었습니다 (현재 edX에서 Haskell mooc을하고 있지만 의심의 여지가 없습니다). 나는 산타, 유령, 요정과 신에 대해 당신에게 동의하지만 확실히 고블린은 아닙니다 : D
John Powell

@MrPurple 나는 그 의견이 그 자체로 질문을 보증한다고 생각합니다. 답변이 너무 길어서 주석을 달 수 없습니다.
Ole Tange

좋아요, 링크 주셔서 감사합니다. gnu parallel을 사용하여 답변을 공식화하면 여기에 게시하겠습니다.
Mr Purple

당신 my_processing.py을 위한 좋은 공식 은 gis.stackexchange.com/a/130337/26897
Mr Purple

4

GNU Parallel 메소드를 사용하는 대신 python mutliprocess 모듈을 사용하여 작업 풀을 작성하고 실행할 수 있습니다. QGIS 설정에 액세스하여 테스트 할 수는 없지만 2.6 이상을 사용하는 경우 멀티 프로세스가 Python 2.6에 추가되었습니다. 이 모듈을 사용하는 데 대한 많은 예제가 온라인에 있습니다.


2
멀티 프로세스를 진행했지만 QGIS의 임베디드 파이썬에 성공적으로 구현 된 것을 아직 보지 못했습니다. 시도해 보니 여러 가지 문제가 발생했습니다. 별도의 질문으로 게시 할 수 있습니다. 내가 알 수있는 한, 이것으로 시작하는 누군가가 공개 할 수있는 예는 없습니다.
Mr Purple

진짜 부끄러운 일입니다. 누군가가 병렬 병렬 처리와 마찬가지로 단일 pyQGIS 함수를 래핑하는 다중 프로세스 모듈의 예를 작성할 수 있다면 우리가 선택한 모든 것을 병렬화 할 수 있습니다.
Mr Purple

동의하지만 현재로서는 QGIS에 액세스 할 수 없습니다.
Steve Barnes

이 창에서 실행하는 경우이 질문 및 대답은 약간의 도움이 될 수 있습니다 gis.stackexchange.com/questions/35279/...
스티브 반즈

@MrPurple과이 하나의 gis.stackexchange.com/questions/114260/… 예를 들어 보자
Steve Barnes

3

다음은 GPU 병렬 솔루션입니다. 약간의주의를 기울이면 QGIS 설치 내에서 가장 근사하게 병렬 리눅스 기반 ogr 또는 saga 알고리즘을 실행할 수 있습니다.

분명히이 솔루션은 gnu 병렬 설치가 필요합니다. 예를 들어 우분투에서 GNU 병렬을 설치하려면 터미널로 이동하여 다음을 입력하십시오.

sudo apt-get -y install parallel

NB : 병렬 쉘 명령을 Popen 또는 하위 프로세스에서 작동하도록 할 수 없었습니다. 따라서 bash 스크립트로 내보내기를 해킹하고 대신 Popen으로 실행했습니다.

파이썬으로 싸인 병렬을 사용하는 특정 쉘 명령은 다음과 같습니다.

parallel ogr2ogr -skipfailures -clipsrc tile_{1}.shp output_{1}.shp input.shp ::: {1..400}

각 {1}은 (는) {1..400} 범위의 숫자로 교체 된 다음 400 개의 쉘 명령을 병렬로 관리하여 i7의 모든 코어를 동시에 사용합니다. :).

다음은 내가 게시 한 예제 문제를 해결하기 위해 작성한 실제 파이썬 코드입니다. 질문의 코드가 끝난 직후에 붙여 넣을 수 있습니다.

import stat
from subprocess import Popen
from subprocess import PIPE
feature_count=tile_layer.dataProvider().featureCount()
subprocess_args=["parallel", \
"ogr2ogr","-skipfailures","-clipsrc",\
os.path.join(output_folder,"tile_"+"{1}"+".shp"),\
os.path.join(output_folder,"output_"+"{1}"+".shp"),\
input_file,\
" ::: ","{1.."+str(feature_count)+"}"]
#Hacky part where I write the shell command to a script file
temp_script=os.path.join(output_folder,"parallelclip.sh")
f = open(temp_script,'w')
f.write("#!/bin/bash\n")
f.write(" ".join(subprocess_args)+'\n')
f.close()
st = os.stat(temp_script)
os.chmod(temp_script, st.st_mode | stat.S_IEXEC)
#End of hacky bash script export
p = Popen([os.path.join(output_folder,"parallelclip.sh")],\
stdin=PIPE, stdout=PIPE, stderr=PIPE)
#Below is the commented out Popen line I couldn't get to work
#p = Popen(subprocess_args, stdin=PIPE, stdout=PIPE, stderr=PIPE)
output, err = p.communicate(b"input data that is passed to subprocess' stdin")
rc = p.returncode
print output
print err

#Delete script and old clip files
os.remove(os.path.join(output_folder,"parallelclip.sh"))
for i in range(feature_count):
    delete_file = os.path.join(output_folder,"tile_"+str(i+1)+".shp")
    nosuff=os.path.splitext(delete_file)[0]
    suffix_list=[]
    suffix_list.append('.shx')
    suffix_list.append('.dbf')
    suffix_list.append('.qpj')
    suffix_list.append('.prj')
    suffix_list.append('.shp')
    suffix_list.append('.cpg')
    for suffix in suffix_list:
        try:
            os.remove(nosuff+suffix)
        except:
            pass

모든 코어가 최대 소음까지 발생하는 것을 볼 때 실제로 무언가라고 말씀 드리겠습니다. :). Ole과 Gnu Parallel을 구축 한 팀에게 특별한 감사를드립니다.

크로스 플랫폼 솔루션이 있으면 좋을 것입니다. qgis 임베디드 파이썬에 대한 멀티 프로세싱 파이썬 모듈을 알아낼 수 있다면 좋을 것입니다.

어쨌든이 솔루션은 저에게 도움이 될 것입니다.


분명히 첫 번째 코드에서 "processing.runalg"행을 주석 처리하여 클립이 병렬로 실행되기 전에 먼저 순차적으로 실행되지 않도록해야합니다. 그 외에는 단순히 질문의 코드 아래에있는 답변의 코드를 복사하여 붙여 넣는 것입니다.
Mr Purple

다른 파일에 병렬로 적용된 "qgis : dissolve"와 같은 많은 처리 명령을 병렬로 실행하려면 purplelinux.co.nz/?p=190
Mr Purple
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.