Song song hoạt động của GIS trong PyQGIS?


15

Một yêu cầu phổ biến trong GIS là áp dụng một công cụ xử lý cho một số tệp hoặc áp dụng một quy trình cho một số tính năng trong một tệp này sang tệp khác.

Phần lớn các hoạt động này song song lúng túng ở chỗ kết quả của các phép tính không ảnh hưởng đến bất kỳ hoạt động nào khác trong vòng lặp. Không chỉ vậy mà thường các tệp đầu vào là mỗi khác biệt.

Một trường hợp kinh điển là việc sắp xếp các tệp hình dạng chống lại các tệp có chứa đa giác để kẹp chúng lại.

Dưới đây là một phương pháp thủ tục cổ điển (đã được thử nghiệm) để đạt được điều này trong tập lệnh python cho QGIS. (fyi đầu ra của các tệp bộ nhớ tạm thời thành các tệp thực hơn một nửa thời gian để xử lý các tệp thử nghiệm của tôi)

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

Điều này sẽ ổn trừ khi tệp đầu vào của tôi là 2GB và tệp cắt đa giác chứa hơn 400 đa giác. Quá trình kết quả mất hơn một tuần trên máy lõi tứ của tôi. Tất cả trong khi ba lõi chỉ là không hoạt động.

Giải pháp tôi có trong đầu là xuất quy trình ra các tệp script và chạy chúng không đồng bộ bằng cách sử dụng song song gnu. Tuy nhiên, có vẻ xấu hổ khi phải bỏ ra khỏi QGIS vào một giải pháp cụ thể cho hệ điều hành thay vì sử dụng một cái gì đó có nguồn gốc từ con trăn QGIS. Vì vậy, câu hỏi của tôi là:

Tôi có thể song song các hoạt động địa lý song song lúng túng bên trong QGIS trăn không?

Nếu không, thì có lẽ ai đó đã có mã để gửi loại công việc này đến các tập lệnh shell không đồng bộ?


Không quen thuộc với đa xử lý trong QGIS, nhưng ví dụ cụ thể về ArcGIS này có thể được sử dụng: gis.stackexchange.com/a/20352/753
blah238

Trông có vẻ thú vị. Tôi sẽ xem những gì tôi có thể làm với nó.
Mr Purple

Câu trả lời:


11

Nếu bạn thay đổi chương trình để đọc tên tệp từ dòng lệnh và chia nhỏ tệp đầu vào của bạn thành các phần nhỏ hơn, bạn có thể thực hiện một số thứ như thế này bằng GNU Parallel:

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

Điều này sẽ chạy 1 công việc cho mỗi lõi.

Tất cả các máy tính mới đều có nhiều lõi, nhưng hầu hết các chương trình đều có bản chất nối tiếp và do đó sẽ không sử dụng nhiều lõi. Tuy nhiên, nhiều nhiệm vụ cực kỳ song song:

  • Chạy cùng một chương trình trên nhiều tệp
  • Chạy cùng một chương trình cho mỗi dòng trong một tệp
  • Chạy cùng một chương trình cho mọi khối trong một tệp

GNU Parallel là một bộ song song chung và giúp dễ dàng chạy các công việc song song trên cùng một máy hoặc trên nhiều máy bạn có quyền truy cập ssh.

Nếu bạn có 32 công việc khác nhau mà bạn muốn chạy trên 4 CPU, một cách đơn giản để song song là chạy 8 công việc trên mỗi CPU:

Lập kế hoạch đơn giản

GNU Parallel thay vào đó sinh ra một quy trình mới khi kết thúc - giữ cho CPU hoạt động và do đó tiết kiệm thời gian:

Lập kế hoạch song song GNU

Cài đặt

Nếu GNU Parallel không được đóng gói cho bản phân phối của bạn, bạn có thể thực hiện cài đặt cá nhân, không yêu cầu quyền truy cập root. Nó có thể được thực hiện trong 10 giây bằng cách làm điều này:

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

Để biết các tùy chọn cài đặt khác, hãy xem http://git.savannah.gnu.org/cgit/abul.git/tree/README

Tìm hiểu thêm

Xem thêm ví dụ: http://www.gnu.org/software/abul/man.html

Xem video giới thiệu: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

Xem qua hướng dẫn: http://www.gnu.org/software/abul/abul_tutorial.html

Đăng ký danh sách email để nhận được hỗ trợ: https://lists.gnu.org/mailman/listinfo/abul


Đây là một cái gì đó giống như tôi sẽ cố gắng và cố gắng, nhưng tôi cần tất cả vẫn còn bên trong con trăn. Dòng cần viết lại để sử dụng nói Popen chẳng hạn ... Một cái gì đó như: từ quá trình nhập Popen, PIPE p = Popen (["song song", "ogr2ogr", "- cliprc", "clip_file * .shp", "đầu ra * .shp "input.shp"], stdin = PIPE, stdout = PIPE, stderr = PIPE) Rắc rối là tôi chưa biết cách chuẩn bị cú pháp đúng cách
Mr Purple

Câu trả lời tuyệt vời. Trước đây tôi chưa từng gặp các nhà khai thác đại tràng ba (hoặc bốn lần) (mặc dù hiện tại tôi đang thực hiện một chương trình Haskell trên edX, vì vậy không có nghi ngờ điều gì tương tự sẽ đến). Tôi đồng ý với bạn về santa, ma, thần tiên và các vị thần, nhưng chắc chắn không phải là yêu tinh: D
John Powell

@MrPurple Tôi nghĩ rằng nhận xét đó tự đảm bảo một câu hỏi. Câu trả lời chắc chắn là quá dài để đưa ra nhận xét.
Ole Tange

OK, cảm ơn vì các liên kết. Nếu tôi xây dựng một câu trả lời bằng cách sử dụng song song gnu, tôi sẽ đăng nó ở đây.
Mr Purple

Một công thức tốt cho bạn my_processing.pycó thể được tìm thấy tại gis.stackexchange.com/a/130337/26897
Mr Purple

4

Thay vì sử dụng phương thức Parallel GNU, bạn có thể sử dụng mô đun mutliprocess của python để tạo ra một nhóm các tác vụ và thực hiện chúng. Tôi không có quyền truy cập vào thiết lập QGIS để kiểm tra nó nhưng đa xử lý đã được thêm vào Python 2.6 vì vậy với điều kiện bạn đang sử dụng 2.6 trở lên thì nó sẽ khả dụng. Có rất nhiều ví dụ trực tuyến về việc sử dụng mô-đun này.


2
Tôi đã thực hiện đa xử lý nhưng tôi vẫn chưa thấy nó được thực hiện thành công trong con trăn nhúng của QGIS. Tôi đã nhấn một số vấn đề khi tôi thử nó. Tôi có thể gửi chúng dưới dạng câu hỏi riêng biệt. Theo như tôi có thể nói không có ví dụ nào có thể truy cập được đối với người bắt đầu với điều này.
Mr Purple

Thật là xấu hổ. Nếu ai đó có thể viết một ví dụ về mô-đun đa xử lý bao hàm một hàm pyQGIS như tôi đã làm với song song gnu thì tất cả chúng ta có thể tắt và song song bất cứ điều gì chúng ta chọn.
Mr Purple

Tôi đồng ý nhưng như tôi đã nói hiện tại tôi không có quyền truy cập vào QGIS.
Steve Barnes

Câu hỏi và câu trả lời này có thể giúp ích nếu bạn đang chạy dưới cửa sổ, gis.stackexchange.com/questions353279/ợi
Steve Barnes

@MrPurple và cái này gis.stackexchange.com/questions/114260/ cho một ví dụ
Steve Barnes

3

Đây là giải pháp song song gnu. Với một số chăm sóc, hầu hết các thuật toán ogr hoặc saga dựa trên linux song song có thể được thực hiện để chạy với nó trong cài đặt QGIS của bạn.

Rõ ràng giải pháp này đòi hỏi phải cài đặt song song gnu. Ví dụ, để cài đặt gnu song song trong Ubuntu, hãy đi đến thiết bị đầu cuối của bạn và nhập

sudo apt-get -y install parallel

Lưu ý: Tôi không thể sử dụng lệnh shell song song để hoạt động trong Popen hoặc quy trình con mà tôi thích, vì vậy tôi đã hack cùng một bản xuất sang tập lệnh bash và thay vào đó chạy bằng Popen.

Đây là lệnh shell cụ thể bằng cách sử dụng song song mà tôi đã bọc trong python

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

Mỗi {1} được hoán đổi một số từ phạm vi {1..400} và sau đó bốn trăm lệnh shell được quản lý bởi gnu song song để sử dụng đồng thời tất cả các lõi của i7 :).

Đây là mã python thực tế tôi đã viết để giải quyết vấn đề ví dụ tôi đã đăng. Người ta có thể dán nó trực tiếp sau khi kết thúc mã trong câu hỏi.

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

Hãy để tôi nói cho bạn biết đó thực sự là một cái gì đó khi bạn thấy tất cả các lõi phát ra tiếng ồn đầy đủ :). Đặc biệt cảm ơn Ole và nhóm đã xây dựng Gnu Parallel.

Thật tuyệt khi có một giải pháp đa nền tảng và thật tuyệt nếu tôi có thể tìm ra mô-đun python đa xử lý cho python nhúng qgis nhưng không phải vậy.

Bất kể giải pháp này sẽ phục vụ tôi và có thể bạn độc đáo.


Rõ ràng người ta nên bình luận dòng "process.runache" trong đoạn mã đầu tiên để clip không chạy tuần tự trước khi nó chạy song song. Ngoài ra, đó đơn giản chỉ là vấn đề sao chép và dán mã từ câu trả lời bên dưới mã trong câu hỏi.
Mr Purple

Nếu bạn chỉ muốn chạy nhiều lệnh xử lý như một tập hợp "qgis: sololve" được áp dụng cho các tệp khác nhau song song thì bạn có thể thấy quy trình của tôi cho việc này tại purplelinux.co.nz/?p=190
Mr Purple
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.