PyQGIS'de CBS operasyonlarına paralel mi?


15

CBS'de yaygın bir gereklilik, bir dizi dosyaya bir işleme aracı uygulamak veya bir dosyadaki birkaç özellik için bir işlemi başka bir dosyaya uygulamaktır.

Bu işlemlerin çoğu, hesaplamaların sonuçlarının döngüdeki diğer işlemleri hiçbir şekilde etkilememesi nedeniyle utanç verici bir şekilde paraleldir. Sadece bu değil, çoğu zaman girdi dosyalarının her biri farklıdır.

Klasik bir durum, şekil dosyalarının, kırpmak için çokgen içeren dosyalara döşenmesidir.

İşte QGIS için bir python betiğinde bunu başarmak için (test edilmiş) klasik bir yöntem. (geçici bellek dosyalarının çıktısının gerçek dosyalara çıktısı, test dosyalarımı işlemek için zamanı yarıya indirdi)

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

Giriş dosyamın 2GB olması ve çokgen kırpma dosyasının 400'den fazla çokgen içermesi dışında bu iyi olur. Ortaya çıkan süreç dört çekirdekli makinemde bir haftadan fazla sürüyor. Bu arada üç çekirdek sadece rölantide.

Kafamdaki çözüm, süreci komut dosyalarına dışa aktarmak ve örneğin gnu paralelini kullanarak eşzamansız olarak çalıştırmaktır. Bununla birlikte, QGIS python'a özgü bir şey kullanmak yerine QGIS'i işletim sistemine özgü bir çözüme bırakmak zorunda olmak utanç verici görünüyor. Benim sorum şu:

Python QGIS içindeki yerel olarak utanç verici şekilde paralel coğrafi işlemleri paralel hale getirebilir miyim?

Değilse, belki de birileri bu tür işleri asenkron kabuk komut dosyalarına göndermek için zaten bir koda sahiptir?



İlgi çekici görünüyor. Bununla ne yapabileceğimi göreceğim.
Bay Mor

Yanıtlar:


11

Programınızı dosya adını komut satırından okuyacak ve giriş dosyanızı daha küçük parçalar halinde ayıracak şekilde değiştirirseniz, GNU Paralel'i kullanarak böyle bir şey yapabilirsiniz:

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

Çekirdek başına 1 iş çalışacaktır.

Tüm yeni bilgisayarların birden çok çekirdeği vardır, ancak çoğu program seri niteliktedir ve bu nedenle birden çok çekirdeği kullanmayacaktır. Bununla birlikte, birçok görev son derece paralelleştirilebilir:

  • Aynı programı birçok dosyada çalıştırın
  • Bir dosyadaki her satır için aynı programı çalıştırın
  • Bir dosyadaki her blok için aynı programı çalıştırın

GNU Parallel genel bir paralelleştiricidir ve işleri aynı makinede veya ssh erişimine sahip olduğunuz birden fazla makinede paralel olarak çalıştırmayı kolaylaştırır.

4 CPU'da çalıştırmak istediğiniz 32 farklı işiniz varsa, paralelleştirmenin basit bir yolu her CPU'da 8 iş çalıştırmaktır:

Basit zamanlama

Bunun yerine GNU Parallel, işlemci bittiğinde yeni bir süreç oluşturur - CPU'ları aktif tutar ve böylece zamandan tasarruf sağlar:

GNU Paralel zamanlama

Kurulum

GNU Parallel dağıtımınız için paketlenmemişse, root erişimi gerektirmeyen kişisel bir kurulum yapabilirsiniz. Bunu yaparak 10 saniye içinde yapılabilir:

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

Diğer kurulum seçenekleri için bkz. Http://git.savannah.gnu.org/cgit/parallel.git/tree/README

Daha fazla bilgi edin

Daha fazla örneğe bakın: http://www.gnu.org/software/parallel/man.html

Giriş videolarını izleyin: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

Eğiticiyi gözden geçirin: http://www.gnu.org/software/parallel/parallel_tutorial.html

Destek almak için e-posta listesine kaydolun: https://lists.gnu.org/mailman/listinfo/parallel


Bu denemek ve denemek için gidiyor gibi bir şey, ama ben tüm python içinde kalmak gerekir. Satır, örneğin Popen demek için yeniden yazılmaya ihtiyaç duyuyor ... Şunun gibi bir şey: Alt işlem içe aktarma Popen, PIPE p = Popen (["paralel", "ogr2ogr", "- clipsrc", "clip_file * .shp", "çıktı * .shp "input.shp"], stdin = PIPE, stdout = PIPE, stderr = PIPE) Sorun şu anda sözdizimini nasıl hazırlayacağımı henüz bilmiyorum
Bay Purple

Müthiş cevap. Daha önce üçlü (veya dörtlü) kolon operatörlerine rastlamamıştım (şu anda edX'te bir Haskell mooc yapıyorum, ancak şüphesiz benzer bir şey gelecek). Sana santa, hayaletler, periler ve tanrılar hakkında katılıyorum, ama kesinlikle goblinler değil: D
John Powell

@MrPurple Bence yorum tek başına bir soru gerektiriyor. Cevap kesinlikle yorum koymak için çok uzun.
Ole Tange

Tamam, bağlantılar için teşekkürler. Eğer gnu paralelini kullanarak bir cevap formüle edersem, buraya göndereceğim.
Bay Purple

Sizin için iyi bir formülasyon gis.stackexchange.com/a/130337/26897my_processing.py adresinde bulunabilir
Bay Purple

4

GNU Parallel yöntemini kullanmak yerine, bir görev havuzu oluşturmak ve bunları yürütmek için python mutliprocess modülünü kullanabilirsiniz. Test etmek için bir QGIS kurulumuna erişimim yok, ancak 2.6 veya daha yeni bir sürümü kullanmanız şartıyla Python 2.6'da çok işlem eklendi. Bu modülü kullanarak çevrimiçi olarak birçok örnek vardır.


2
Çok işlemciyi denedim ama henüz QGIS'in gömülü python'unda başarılı bir şekilde alıştırıldığını görmedim. Denediğim gibi bir dizi sorunu vurdum. Onları ayrı sorular olarak gönderebilirim. Anlayabildiğim kadarıyla, bununla başlayan birinin erişebileceği halka açık örnekler yok.
Bay Purple

Gerçek bir utanç. Birisi, gnu paraleliyle yaptığım gibi tek bir pyQGIS işlevini saran çok işlem modülünün bir örneğini yazabilseydi, o zaman hepimiz gidip ne seçersek seçelim.
Bay Purple

Katılıyorum ama dediğim gibi şu anda bir QGIS'e erişimim yok.
Steve Barnes

Bu soru ve cevap Windows altında çalışıyorsanız bazı yardımcı olabilir, gis.stackexchange.com/questions/35279/…
Steve Barnes

@MrPurple ve bu gis.stackexchange.com/questions/114260/… bir örnek veriyor
Steve Barnes

3

İşte GNU paralel çözüm. Biraz özen göstererek, QGIS kurulumunuzda onunla çalışmak için en utanç verici şekilde paralel linux tabanlı ogr veya saga algoritmaları yapılabilir.

Açıkçası bu çözüm gnu paralel kurulumunu gerektirir. Örneğin gnu paralel'i Ubuntu'ya kurmak için terminalinize gidin ve yazın

sudo apt-get -y install parallel

Not: Paralel kabuk komutunu, tercih edeceğim Popen veya alt işlemde çalıştıramadım, bu yüzden birlikte bir bash komut dosyasına bir ihracat kesmek ve bunun yerine Popen ile koştu.

İşte python sarılmış paralel kullanarak belirli kabuk komutu

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

Her {1}, {1..400} aralığından bir sayı için değiştirilir ve daha sonra dört yüz kabuk komutu, i7'imin tüm çekirdeklerini aynı anda kullanmak için gnu tarafından yönetilir.

İşte gönderdiğim örnek sorunu çözmek için yazdığım gerçek python kodu. Söz konusu kodun bitiminden sonra doğrudan yapıştırılabilir.

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

Tüm çekirdeklerin tam gürültüye ateş ettiğini gördüğünüzde size bir şey söyleyeyim :). Ole ve Gnu Parallel'ı oluşturan takıma özel teşekkürler.

Bir çapraz platform çözümüne sahip olmak güzel olurdu ve qgis gömülü python için çok işlemli python modülünü anlayabilirdim ama ne yazık ki değildi.

Ne olursa olsun bu çözüm bana ve belki de güzel hizmet edecek.


Açıkçası, ilk kod parçasındaki "processing.runalg" satırını yorumlamak gerekir, böylece klip paralel olarak çalıştırılmadan önce sırayla çalıştırılmaz. Bunun dışında, sadece kodun sorudaki kodun altındaki cevaptan kopyalanması ve yapıştırılması meselesidir.
Bay Purple

Paralel olarak farklı dosyalara uygulanan bir dizi "qgis: dissolve" gibi birçok işlem komutunu çalıştırmak istiyorsanız, bunun için işlemimi purplelinux.co.nz/?p=190
Bay Purple
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.