はじめに
multiprocessing モジュール が含まれる Python 2.6 がArcGIS 製品に入ってきたのは、ArcGIS 10.0 の登場がはじめでした(ArcGIS 10.0 国内リリース:2010年10月22日)。それ以降、米国 Esri の配信している Blog でも Python Multiprocessing – Approaches and Considerations(2011年8月)、Multiprocessing with ArcGIS – Approaches and Considerations (Part 1):2012年9月としてマルチプロセス処理について記事で取り上げられたのをはじめ、近年でも世界中から多くの開発者が集まるEsri Developer Summit で Parallel Python: Multiprocessing with ArcPy:2017年3月 の動画、Vector and Raster Multiprocessing with ArcPy:2018年3月 の動画 としてテクニカル セッションとして取り上げられています。
マルチプロセス処理
ArcGIS Pro 動作環境 に見られるような高スペックのハードウェア(64-bit OSが標準、CPU 4コアを推奨、メモリも最適 16GB以上)が普及してきた一方で、分析や処理に使われるデータ量も飛躍的に増加しており、効率的な分析や処理が必要な状況は今も続いています。
そのような中で、今回は、ArcGIS プラットフォームの拡張手段として定着している ArcPy とPython でのマルチプロセス処理をとりあげ、実装の要点となる箇所とコーディングパターンをサンプルを交えつつ紹介したいと思います。
さまざまな処理での実際のコーディングは、関連情報に示したものを確認いただきつつ、実際にコードを書いて試してみることをお勧めしますが、本記事を参照して並列処理実装のポイントを掴んでいただき、現在のワークフローに上手く取り入れる一助となればと思います。
ベストプラクティス
関連情報に示した各種資料では、ArcPy とPython を使用したマルチプロセス処理のベストプラクティスとして、次のようなことが言われています。
- テンポラリの結果を保持するためには、高速に動作するため、in_memory ワークスペースを使うのを推奨。
- ファイル ジオデータベース(参考:ジオデータベースの概要)や、GRID ラスターへの書き込みは避ける。
これらのデータ形式はスキーマロックや同期の問題を引き起こすことがあり、これはファイル ジオデータベースとGRIDラスターが同時書き込みをサポートしていないためで、つまり、一度に1つのプロセスだけが書き込むことができる仕様であるということです。ArcGIS で開いていたフィーチャ クラスを、ArcPy で変更しようとすると、この問題が発生していたのは目にしたことがあるかと思います。さらに、ファイル ジオデータベースを所持していて、多くのフィーチャクラスに対して書き込みを行おうとすると、その問題は拡大されます。すべてのフィーチャ クラスが独立して存在していたとしても、ファイル ジオデータベース内のフィーチャクラスに書き込むことができるのは一度に1つのフィーチャ クラスです。
- スクリプトの実行には 64-bit のPython 実行環境を使用する。
ArcGIS Pro 1.4 以上、もしくはArcGIS Server 10.5 以上、またはBackground Geoprocessing (64-bit) をインストールした ArcGIS Desktop 10.5 以上の 64-bit Python 実行環境を使用。64-bit の実行環境は32-bitのメモリ制限(4GB)で失敗するような、大きなデータに対する問題を解決できる可能性があるからです。 特に実装にあたっては、2つ目に挙げているファイル ジオデータベースの使用には注意する必要があります。少なくとも各プロセスでの処理を記載するワーカー関数での書込み先として同じファイル ジオデータベースを使用しないようにすべきですが、マスター関数でそれらを使用して、多数のシェープ ファイルや、個々のファイル ジオデータベースを単一ソースにマージするのに使用することは可能です。
*複数のプロセスからの書込み先として、ワーカー関数でのエンタープライズ ジオデータベースを書込み先として使用するのも、一つの方法です。
マルチプロセス処理のサンプル
今回のサンプルは、47都道県別のフォルダ下に複数のシェープファイルが入っており、それらを47都道府県別のファイル ジオデータベースを作成後、それぞれフィーチャクラスに変換する実装サンプルコードです。 実装する際のポイントは、上記のベストプラクティスで書いているように、ファイル ジオデータベースへの書込み時にロックされるので、「1都道府県フォルダのシェープファイルは1都道府県ファイル ジオデータベースでのフィーチャクラスへの変換となるようにコードを書くこと」です。
実際にコーディングパターンとして見ていきましょう。
1) ワーカー関数:batch_convert
コーディングパターンとしては、まずはワーカー関数を通常の ArcPyでの処理と同様に書きます。このときに注意するべきなのは、ベストプラクティスで書いたように、このワーカー関数での処理がプロセスでの処理に相当するので、複数プロセス(複数のワーカー関数)から書込み先としてアクセスする必要がある場合はエンタープライズ ジオデータベースを利用するか、同じファイル ジオデータベースを使用しないようにすることです。
<SPAN class="keyword token">def</SPAN> <SPAN class="token function">batch_convert</SPAN><SPAN class="punctuation token">(</SPAN>inws<SPAN class="punctuation token">,</SPAN> outws<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN>
<SPAN class="string token">'''
1プロセスで実行する処理(ワーカー関数):
ファイル ジオデータベースへの書込みは複数プロセスでできないため、
・1都道府県のフォルダ下の複数シェープ ファイルを
・1都道府県のファイル ジオデータベース下の複数フィーチャ クラスに変換
するように記載
'''</SPAN>
<SPAN class="comment token">#print("変換: {0} ⇒ {1}\n".format(inws,outws))</SPAN>
<SPAN class="keyword token">if</SPAN> <SPAN class="operator token">not</SPAN> arcpy<SPAN class="punctuation token">.</SPAN>Exists<SPAN class="punctuation token">(</SPAN>outws<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN>
outfolder<SPAN class="operator token">=</SPAN>os<SPAN class="punctuation token">.</SPAN>path<SPAN class="punctuation token">.</SPAN>dirname<SPAN class="punctuation token">(</SPAN>outws<SPAN class="punctuation token">)</SPAN>
foldername<SPAN class="operator token">=</SPAN>os<SPAN class="punctuation token">.</SPAN>path<SPAN class="punctuation token">.</SPAN>basename<SPAN class="punctuation token">(</SPAN>outws<SPAN class="punctuation token">)</SPAN>
arcpy<SPAN class="punctuation token">.</SPAN>CreateFileGDB_management<SPAN class="punctuation token">(</SPAN>outfolder<SPAN class="punctuation token">,</SPAN>foldername<SPAN class="punctuation token">,</SPAN><SPAN class="string token">"CURRENT"</SPAN><SPAN class="punctuation token">)</SPAN>
arcpy<SPAN class="punctuation token">.</SPAN>env<SPAN class="punctuation token">.</SPAN>workspace <SPAN class="operator token">=</SPAN> inws
fcs <SPAN class="operator token">=</SPAN> arcpy<SPAN class="punctuation token">.</SPAN>ListFeatureClasses<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="keyword token">for</SPAN> fc <SPAN class="keyword token">in</SPAN> fcs<SPAN class="punctuation token">:</SPAN>
l<SPAN class="operator token">=</SPAN>len<SPAN class="punctuation token">(</SPAN>fc<SPAN class="punctuation token">)</SPAN>
infc<SPAN class="operator token">=</SPAN>os<SPAN class="punctuation token">.</SPAN>path<SPAN class="punctuation token">.</SPAN>splitext<SPAN class="punctuation token">(</SPAN>fc<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="number token">0</SPAN><SPAN class="punctuation token">]</SPAN>
<SPAN class="comment token"># 0埋めした4桁の名前にフィーチャクラス名を変更</SPAN>
<SPAN class="comment token"># 例) P101_CITY.shp → P0101_CITY</SPAN>
newfc <SPAN class="operator token">=</SPAN> fc<SPAN class="punctuation token">[</SPAN><SPAN class="punctuation token">:</SPAN><SPAN class="number token">1</SPAN><SPAN class="punctuation token">]</SPAN><SPAN class="operator token">+</SPAN>fc<SPAN class="punctuation token">[</SPAN><SPAN class="number token">1</SPAN><SPAN class="punctuation token">:</SPAN>l<SPAN class="number token">-4</SPAN><SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">.</SPAN>zfill<SPAN class="punctuation token">(</SPAN><SPAN class="number token">4</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="comment token"># 既存フィーチャクラスが存在する場合はAppend</SPAN>
<SPAN class="comment token"># 存在しない場合はFeatureClassToFeatureClass</SPAN>
<SPAN class="keyword token">if</SPAN> arcpy<SPAN class="punctuation token">.</SPAN>Exists<SPAN class="punctuation token">(</SPAN>os<SPAN class="punctuation token">.</SPAN>path<SPAN class="punctuation token">.</SPAN>join<SPAN class="punctuation token">(</SPAN>outws<SPAN class="punctuation token">,</SPAN>newfc<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN>
outfc<SPAN class="operator token">=</SPAN>os<SPAN class="punctuation token">.</SPAN>path<SPAN class="punctuation token">.</SPAN>join<SPAN class="punctuation token">(</SPAN>outws<SPAN class="punctuation token">,</SPAN>newfc<SPAN class="punctuation token">)</SPAN>
arcpy<SPAN class="punctuation token">.</SPAN>Append_management<SPAN class="punctuation token">(</SPAN>fc<SPAN class="punctuation token">,</SPAN>outfc<SPAN class="punctuation token">)</SPAN>
<SPAN class="keyword token">else</SPAN><SPAN class="punctuation token">:</SPAN>
arcpy<SPAN class="punctuation token">.</SPAN>FeatureClassToFeatureClass_conversion<SPAN class="punctuation token">(</SPAN>fc<SPAN class="punctuation token">,</SPAN>outws<SPAN class="punctuation token">,</SPAN>newfc<SPAN class="punctuation token">)</SPAN>
<SPAN class="keyword token">del</SPAN> fcs
<SPAN class="keyword token">return</SPAN> <SPAN class="string token">" 変換済:{0}"</SPAN><SPAN class="punctuation token">.</SPAN>format<SPAN class="punctuation token">(</SPAN>outws<SPAN class="punctuation token">)</SPAN>
<SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>
2) ワーカー関数のラッパー:multi_run_batch_convert
マルチプロセスからワーカー関数を指定する際、ワーカー関数の引数が単独の場合は不要ですが、サンプルのように複数の引数を渡す必要がある場合は、ラッパー関数を用意すると便利です。
<SPAN class="keyword token">def</SPAN> <SPAN class="token function">multi_run_batch_convert</SPAN><SPAN class="punctuation token">(</SPAN>args<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN>
<SPAN class="string token">'''
batch_convert の wrapper:
複数の引数を実行処理に渡すためのラッパー
'''</SPAN>
<SPAN class="keyword token">return</SPAN> batch_convert<SPAN class="punctuation token">(</SPAN><SPAN class="operator token">*</SPAN>args<SPAN class="punctuation token">)</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>
3) マルチプロセスの処理:exec_batch_convert
ワーカー関数へ渡す2つの引数(inws, outws)を params にリスト化していれます。
その後、
pool = multiprocessing.Pool(cpu_cnt) で確保した pool に
results = pool.map(multi_run_batch_convert , params) を指定します。
第1引数:処理するワーカー関数名(今回の場合はラッパー関数) multi_run_batch_convert
第2引数:リストかしたパラメータ params
<SPAN class="keyword token">def</SPAN> <SPAN class="token function">exec_batch_convert</SPAN><SPAN class="punctuation token">(</SPAN>infolder<SPAN class="punctuation token">,</SPAN>outfolder<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN>
<SPAN class="string token">'''
マルチプロセスでの処理(マスター関数):
'''</SPAN>
<SPAN class="keyword token">try</SPAN><SPAN class="punctuation token">:</SPAN>
start<SPAN class="operator token">=</SPAN>datetime<SPAN class="punctuation token">.</SPAN>datetime<SPAN class="punctuation token">.</SPAN>now<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="keyword token">print</SPAN> <SPAN class="string token">"-- Strat: Multiprocess_ShapefileToFeatureClassWithRename --:"</SPAN><SPAN class="punctuation token">,</SPAN>start
cpu_cnt<SPAN class="operator token">=</SPAN>multiprocessing<SPAN class="punctuation token">.</SPAN>cpu_count<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN>
arcpy<SPAN class="punctuation token">.</SPAN>env<SPAN class="punctuation token">.</SPAN>workspace <SPAN class="operator token">=</SPAN> infolder
inwss <SPAN class="operator token">=</SPAN> arcpy<SPAN class="punctuation token">.</SPAN>ListWorkspaces<SPAN class="punctuation token">(</SPAN><SPAN class="string token">"*"</SPAN><SPAN class="punctuation token">,</SPAN><SPAN class="string token">"Folder"</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="comment token"># 各プロセスへ渡すパラメータをリスト化</SPAN>
params<SPAN class="operator token">=</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="punctuation token">]</SPAN>
<SPAN class="keyword token">for</SPAN> inws <SPAN class="keyword token">in</SPAN> inwss<SPAN class="punctuation token">:</SPAN>
param1<SPAN class="operator token">=</SPAN>inws <SPAN class="comment token"># 都道府県フォルダ(シェープファイルが入っている)</SPAN>
gdbname<SPAN class="operator token">=</SPAN><SPAN class="string token">"{0}.gdb"</SPAN><SPAN class="punctuation token">.</SPAN>format<SPAN class="punctuation token">(</SPAN>os<SPAN class="punctuation token">.</SPAN>path<SPAN class="punctuation token">.</SPAN>basename<SPAN class="punctuation token">(</SPAN>inws<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN>
param2<SPAN class="operator token">=</SPAN>os<SPAN class="punctuation token">.</SPAN>path<SPAN class="punctuation token">.</SPAN>join<SPAN class="punctuation token">(</SPAN>outfolder<SPAN class="punctuation token">,</SPAN>gdbname<SPAN class="punctuation token">)</SPAN> <SPAN class="comment token"># 都道府県ファイルジオデータベース</SPAN>
params<SPAN class="punctuation token">.</SPAN>append<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">(</SPAN>param1<SPAN class="punctuation token">,</SPAN>param2<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="keyword token">if</SPAN> len<SPAN class="punctuation token">(</SPAN>inwss<SPAN class="punctuation token">)</SPAN> <SPAN class="operator token"><</SPAN> cpu_cnt<SPAN class="punctuation token">:</SPAN> <SPAN class="comment token"># 処理フォルダ数がCPUコアより少ない場合無駄なプロセスを起動不要</SPAN>
cpu_cnt<SPAN class="operator token">=</SPAN>len<SPAN class="punctuation token">(</SPAN>inwss<SPAN class="punctuation token">)</SPAN>
pool <SPAN class="operator token">=</SPAN> multiprocessing<SPAN class="punctuation token">.</SPAN>Pool<SPAN class="punctuation token">(</SPAN>cpu_cnt<SPAN class="punctuation token">)</SPAN> <SPAN class="comment token">#cpu数分のpythonプロセスを作成</SPAN>
results<SPAN class="operator token">=</SPAN>pool<SPAN class="punctuation token">.</SPAN>map<SPAN class="punctuation token">(</SPAN>multi_run_batch_convert<SPAN class="punctuation token">,</SPAN>params<SPAN class="punctuation token">)</SPAN> <SPAN class="comment token">#割り当てプロセスで順次実行される</SPAN>
pool<SPAN class="punctuation token">.</SPAN>close<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN>
pool<SPAN class="punctuation token">.</SPAN>join<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="comment token"># 各プロセスでの処理結果を出力</SPAN>
<SPAN class="keyword token">for</SPAN> r <SPAN class="keyword token">in</SPAN> results<SPAN class="punctuation token">:</SPAN>
<SPAN class="keyword token">print</SPAN><SPAN class="punctuation token">(</SPAN>r<SPAN class="punctuation token">)</SPAN>
<SPAN class="comment token"># 都道府県別のファイル ジオデータベース内のフィーチャ クラスを統合して</SPAN>
<SPAN class="comment token"># 全国版を作成する場合はここに記載します</SPAN>
<SPAN class="comment token"># ~省略~</SPAN>
fin<SPAN class="operator token">=</SPAN>datetime<SPAN class="punctuation token">.</SPAN>datetime<SPAN class="punctuation token">.</SPAN>now<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="keyword token">print</SPAN> <SPAN class="string token">"-- Finish: Multiprocess_ShapefileToFeatureClassWithRename --:"</SPAN><SPAN class="punctuation token">,</SPAN>fin
<SPAN class="keyword token">print</SPAN> <SPAN class="string token">" Elapsed time:"</SPAN><SPAN class="punctuation token">,</SPAN> fin<SPAN class="operator token">-</SPAN>start
<SPAN class="keyword token">except</SPAN><SPAN class="punctuation token">:</SPAN>
<SPAN class="keyword token">print</SPAN> traceback<SPAN class="punctuation token">.</SPAN>format_exc<SPAN class="punctuation token">(</SPAN>sys<SPAN class="punctuation token">.</SPAN>exc_info<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="number token">2</SPAN><SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>
完成版のサンプルコード
上記までのコーディングパターンに従って実装したPythonスクリプト(Multiprocess_Sample.py)の infolder, outfolder をご自分の環境のものに変更してPython の実行環境から実行すれば、マルチプロセスでデータ変換が行われます。
<SPAN class="comment token">#coding:cp932</SPAN>
<SPAN class="keyword token">import</SPAN> arcpy<SPAN class="punctuation token">,</SPAN>os
<SPAN class="keyword token">import</SPAN> sys
<SPAN class="keyword token">import</SPAN> multiprocessing
<SPAN class="keyword token">import</SPAN> datetime
<SPAN class="keyword token">import</SPAN> traceback
reload<SPAN class="punctuation token">(</SPAN>sys<SPAN class="punctuation token">)</SPAN>
sys<SPAN class="punctuation token">.</SPAN>setdefaultencoding<SPAN class="punctuation token">(</SPAN><SPAN class="string token">'cp932'</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="keyword token">def</SPAN> <SPAN class="token function">multi_run_batch_convert</SPAN><SPAN class="punctuation token">(</SPAN>args<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN>
<SPAN class="string token">'''
batch_convert の wrapper:
複数の引数を実行処理に渡すためのラッパー
'''</SPAN>
<SPAN class="keyword token">return</SPAN> batch_convert<SPAN class="punctuation token">(</SPAN><SPAN class="operator token">*</SPAN>args<SPAN class="punctuation token">)</SPAN>
<SPAN class="keyword token">def</SPAN> <SPAN class="token function">batch_convert</SPAN><SPAN class="punctuation token">(</SPAN>inws<SPAN class="punctuation token">,</SPAN> outws<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN>
<SPAN class="string token">'''
1プロセスで実行する処理(ワーカー関数):
ファイル ジオデータベースへの書込みは複数プロセスでできないため、
・1都道府県のフォルダ下の複数シェープ ファイルを
・1都道府県のファイル ジオデータベース下の複数フィーチャ クラスに変換
するように記載
'''</SPAN>
<SPAN class="comment token">#print("変換: {0} ⇒ {1}\n".format(inws,outws))</SPAN>
<SPAN class="keyword token">if</SPAN> <SPAN class="operator token">not</SPAN> arcpy<SPAN class="punctuation token">.</SPAN>Exists<SPAN class="punctuation token">(</SPAN>outws<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN>
outfolder<SPAN class="operator token">=</SPAN>os<SPAN class="punctuation token">.</SPAN>path<SPAN class="punctuation token">.</SPAN>dirname<SPAN class="punctuation token">(</SPAN>outws<SPAN class="punctuation token">)</SPAN>
foldername<SPAN class="operator token">=</SPAN>os<SPAN class="punctuation token">.</SPAN>path<SPAN class="punctuation token">.</SPAN>basename<SPAN class="punctuation token">(</SPAN>outws<SPAN class="punctuation token">)</SPAN>
arcpy<SPAN class="punctuation token">.</SPAN>CreateFileGDB_management<SPAN class="punctuation token">(</SPAN>outfolder<SPAN class="punctuation token">,</SPAN>foldername<SPAN class="punctuation token">,</SPAN><SPAN class="string token">"CURRENT"</SPAN><SPAN class="punctuation token">)</SPAN>
arcpy<SPAN class="punctuation token">.</SPAN>env<SPAN class="punctuation token">.</SPAN>workspace <SPAN class="operator token">=</SPAN> inws
fcs <SPAN class="operator token">=</SPAN> arcpy<SPAN class="punctuation token">.</SPAN>ListFeatureClasses<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="keyword token">for</SPAN> fc <SPAN class="keyword token">in</SPAN> fcs<SPAN class="punctuation token">:</SPAN>
l<SPAN class="operator token">=</SPAN>len<SPAN class="punctuation token">(</SPAN>fc<SPAN class="punctuation token">)</SPAN>
infc<SPAN class="operator token">=</SPAN>os<SPAN class="punctuation token">.</SPAN>path<SPAN class="punctuation token">.</SPAN>splitext<SPAN class="punctuation token">(</SPAN>fc<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="number token">0</SPAN><SPAN class="punctuation token">]</SPAN>
<SPAN class="comment token"># 0埋めした4桁の名前にフィーチャクラス名を変更</SPAN>
<SPAN class="comment token"># 例) P101_CITY.shp → P0101_CITY</SPAN>
newfc <SPAN class="operator token">=</SPAN> fc<SPAN class="punctuation token">[</SPAN><SPAN class="punctuation token">:</SPAN><SPAN class="number token">1</SPAN><SPAN class="punctuation token">]</SPAN><SPAN class="operator token">+</SPAN>fc<SPAN class="punctuation token">[</SPAN><SPAN class="number token">1</SPAN><SPAN class="punctuation token">:</SPAN>l<SPAN class="number token">-4</SPAN><SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">.</SPAN>zfill<SPAN class="punctuation token">(</SPAN><SPAN class="number token">4</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="comment token"># 既存フィーチャクラスが存在する場合はAppend</SPAN>
<SPAN class="comment token"># 存在しない場合はFeatureClassToFeatureClass</SPAN>
<SPAN class="keyword token">if</SPAN> arcpy<SPAN class="punctuation token">.</SPAN>Exists<SPAN class="punctuation token">(</SPAN>os<SPAN class="punctuation token">.</SPAN>path<SPAN class="punctuation token">.</SPAN>join<SPAN class="punctuation token">(</SPAN>outws<SPAN class="punctuation token">,</SPAN>newfc<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN>
outfc<SPAN class="operator token">=</SPAN>os<SPAN class="punctuation token">.</SPAN>path<SPAN class="punctuation token">.</SPAN>join<SPAN class="punctuation token">(</SPAN>outws<SPAN class="punctuation token">,</SPAN>newfc<SPAN class="punctuation token">)</SPAN>
arcpy<SPAN class="punctuation token">.</SPAN>Append_management<SPAN class="punctuation token">(</SPAN>fc<SPAN class="punctuation token">,</SPAN>outfc<SPAN class="punctuation token">)</SPAN>
<SPAN class="keyword token">else</SPAN><SPAN class="punctuation token">:</SPAN>
arcpy<SPAN class="punctuation token">.</SPAN>FeatureClassToFeatureClass_conversion<SPAN class="punctuation token">(</SPAN>fc<SPAN class="punctuation token">,</SPAN>outws<SPAN class="punctuation token">,</SPAN>newfc<SPAN class="punctuation token">)</SPAN>
<SPAN class="keyword token">del</SPAN> fcs
<SPAN class="keyword token">return</SPAN> <SPAN class="string token">" 変換済:{0}"</SPAN><SPAN class="punctuation token">.</SPAN>format<SPAN class="punctuation token">(</SPAN>outws<SPAN class="punctuation token">)</SPAN>
<SPAN class="keyword token">def</SPAN> <SPAN class="token function">exec_batch_convert</SPAN><SPAN class="punctuation token">(</SPAN>infolder<SPAN class="punctuation token">,</SPAN>outfolder<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN>
<SPAN class="string token">'''
マルチプロセスでの処理(マスター関数):
'''</SPAN>
<SPAN class="keyword token">try</SPAN><SPAN class="punctuation token">:</SPAN>
start<SPAN class="operator token">=</SPAN>datetime<SPAN class="punctuation token">.</SPAN>datetime<SPAN class="punctuation token">.</SPAN>now<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="keyword token">print</SPAN> <SPAN class="string token">"-- Strat: Multiprocess_ShapefileToFeatureClassWithRename --:"</SPAN><SPAN class="punctuation token">,</SPAN>start
cpu_cnt<SPAN class="operator token">=</SPAN>multiprocessing<SPAN class="punctuation token">.</SPAN>cpu_count<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN>
arcpy<SPAN class="punctuation token">.</SPAN>env<SPAN class="punctuation token">.</SPAN>workspace <SPAN class="operator token">=</SPAN> infolder
inwss <SPAN class="operator token">=</SPAN> arcpy<SPAN class="punctuation token">.</SPAN>ListWorkspaces<SPAN class="punctuation token">(</SPAN><SPAN class="string token">"*"</SPAN><SPAN class="punctuation token">,</SPAN><SPAN class="string token">"Folder"</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="comment token"># 各プロセスへ渡すパラメータをリスト化</SPAN>
params<SPAN class="operator token">=</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="punctuation token">]</SPAN>
<SPAN class="keyword token">for</SPAN> inws <SPAN class="keyword token">in</SPAN> inwss<SPAN class="punctuation token">:</SPAN>
param1<SPAN class="operator token">=</SPAN>inws <SPAN class="comment token"># 都道府県フォルダ(シェープファイルが入っている)</SPAN>
gdbname<SPAN class="operator token">=</SPAN><SPAN class="string token">"{0}.gdb"</SPAN><SPAN class="punctuation token">.</SPAN>format<SPAN class="punctuation token">(</SPAN>os<SPAN class="punctuation token">.</SPAN>path<SPAN class="punctuation token">.</SPAN>basename<SPAN class="punctuation token">(</SPAN>inws<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN>
param2<SPAN class="operator token">=</SPAN>os<SPAN class="punctuation token">.</SPAN>path<SPAN class="punctuation token">.</SPAN>join<SPAN class="punctuation token">(</SPAN>outfolder<SPAN class="punctuation token">,</SPAN>gdbname<SPAN class="punctuation token">)</SPAN> <SPAN class="comment token"># 都道府県ファイルジオデータベース</SPAN>
params<SPAN class="punctuation token">.</SPAN>append<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">(</SPAN>param1<SPAN class="punctuation token">,</SPAN>param2<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="keyword token">if</SPAN> len<SPAN class="punctuation token">(</SPAN>inwss<SPAN class="punctuation token">)</SPAN> <SPAN class="operator token"><</SPAN> cpu_cnt<SPAN class="punctuation token">:</SPAN> <SPAN class="comment token"># 処理フォルダ数がCPUコアより少ない場合無駄なプロセスを起動不要</SPAN>
cpu_cnt<SPAN class="operator token">=</SPAN>len<SPAN class="punctuation token">(</SPAN>inwss<SPAN class="punctuation token">)</SPAN>
pool <SPAN class="operator token">=</SPAN> multiprocessing<SPAN class="punctuation token">.</SPAN>Pool<SPAN class="punctuation token">(</SPAN>cpu_cnt<SPAN class="punctuation token">)</SPAN> <SPAN class="comment token">#cpu数分のpythonプロセスを作成</SPAN>
results<SPAN class="operator token">=</SPAN>pool<SPAN class="punctuation token">.</SPAN>map<SPAN class="punctuation token">(</SPAN>multi_run_batch_convert<SPAN class="punctuation token">,</SPAN>params<SPAN class="punctuation token">)</SPAN> <SPAN class="comment token">#割り当てプロセスで順次実行される</SPAN>
pool<SPAN class="punctuation token">.</SPAN>close<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN>
pool<SPAN class="punctuation token">.</SPAN>join<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="comment token"># 各プロセスでの処理結果を出力</SPAN>
<SPAN class="keyword token">for</SPAN> r <SPAN class="keyword token">in</SPAN> results<SPAN class="punctuation token">:</SPAN>
<SPAN class="keyword token">print</SPAN><SPAN class="punctuation token">(</SPAN>r<SPAN class="punctuation token">)</SPAN>
<SPAN class="comment token"># 都道府県別のファイル ジオデータベース内のフィーチャ クラスを統合して</SPAN>
<SPAN class="comment token"># 全国版を作成する場合はここに記載します</SPAN>
<SPAN class="comment token"># ~省略~</SPAN>
fin<SPAN class="operator token">=</SPAN>datetime<SPAN class="punctuation token">.</SPAN>datetime<SPAN class="punctuation token">.</SPAN>now<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="keyword token">print</SPAN> <SPAN class="string token">"-- Finish: Multiprocess_ShapefileToFeatureClassWithRename --:"</SPAN><SPAN class="punctuation token">,</SPAN>fin
<SPAN class="keyword token">print</SPAN> <SPAN class="string token">" Elapsed time:"</SPAN><SPAN class="punctuation token">,</SPAN> fin<SPAN class="operator token">-</SPAN>start
<SPAN class="keyword token">except</SPAN><SPAN class="punctuation token">:</SPAN>
<SPAN class="keyword token">print</SPAN> traceback<SPAN class="punctuation token">.</SPAN>format_exc<SPAN class="punctuation token">(</SPAN>sys<SPAN class="punctuation token">.</SPAN>exc_info<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="number token">2</SPAN><SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="keyword token">def</SPAN> <SPAN class="token function">setup_batch_convert</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN>
<SPAN class="string token">'''
コマンドプロンプトからの実行パラメータを設定:
都道府県別のシェープ ファイルが入った元フォルダ :infolder
例)
|-Shapefiles
|- 01_北海道
|-P101_CITY.shp
|-L102_RIVER.shp
・・・・・
|- 02_青森県
|- 03_岩手県
・・・・・
都道府県別のファイル ジオデータベースの作成先フォルダ :outfolder
例)
|-Filegdbs
|- 01_北海道.gdb
|-P0101_CITY
|-L0102_RIVER
・・・・・
|- 02_青森県.gdb
|- 03_岩手県.gdb
・・・・・
'''</SPAN>
infolder<SPAN class="operator token">=</SPAN>r<SPAN class="string token">"E:\DATA\Shapefiles"</SPAN> <SPAN class="comment token">#都道府県別のシェープファイルが入った元フォルダ</SPAN>
outfolder<SPAN class="operator token">=</SPAN>r<SPAN class="string token">"E:\DATA\Filegdbs"</SPAN> <SPAN class="comment token">#都道府県別のファイル ジオデータベースの作成先フォルダ</SPAN>
exec_batch_convert<SPAN class="punctuation token">(</SPAN>infolder<SPAN class="punctuation token">,</SPAN>outfolder<SPAN class="punctuation token">)</SPAN>
<SPAN class="keyword token">if</SPAN> __name__ <SPAN class="operator token">==</SPAN> <SPAN class="string token">'__main__'</SPAN><SPAN class="punctuation token">:</SPAN>
setup_batch_convert<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>
64-bit 環境でのPython スクリプトの実行例
なお、ベストプラクティスで書いたように、64-bitの Python環境から実行してください。Pythonスクリプトの実行例としてArcGIS Desktop、ArcGIS Proでの例を載せておきます。
実行例)ArcGIS Desktop 10.6.1
>C:\Python27\ArcGISx6410.6\python.exe Multiprocess_Sample.py
実行例)ArcGIS Pro 2.2
>"c:\Program Files\ArcGIS\Pro\bin\Python\scripts\propy.bat" Multiprocess_Sample.py
参考となるブログやWebサイト
・Using Arcpy with multiprocessing – Part 1・Using Arcpy with multiprocessing – Part 2・Using Arcpy with multiprocessing – Part 3・Python Multiprocessing – Approaches and Considerations(2011年8月:ArcGIS 10.0 環境)・Multiprocessing with ArcGIS – Approaches and Considerations (Part 1)(2012年9月:ArcGIS 10.1 環境)・ペンシルバニア州立大学の John A. Dutton eラーニング研究所のマテリアル GEOG 489 - Advanced Python Programming for GIS - 1.6.6 ArcPy multiprocessing examples
参考となる動画
・Parallel Python: Multiprocessing with ArcPy(2017年3月のEsri Developer Summmit)・Vector and Raster Multiprocessing with ArcPy(2018年3月のEsri Developer Summit)