🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
並列処理

複数の計算が同時に実行される手法

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

3394閲覧

shutil.make_archiveをマルチスレッドで走らせるとランダムにファイルが抜ける

退会済みユーザー

退会済みユーザー

総合スコア0

並列処理

複数の計算が同時に実行される手法

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/02/11 21:15

コマンド引数として与えたパス内のサブディレクトリをそれぞれzip化し、元のサブディレクトリは削除するというスクリプトを書いています。
シングルスレッドの場合は問題なく動く(auto_zip())のですが、concurrent.futures.ThreadPoolExecutor()を使いマルチスレッドで行う(auto_zip_multi_thread())と圧縮後のzipにいくつかのファイルが含まれていないことがあります。
ファイルの何割が抜けているのかは毎回異なり、同じディレクトリでも複数回実行すると毎回違う結果になります。
欠損なく処理が終わることもあります。
このように再現性がないのですが、どこをどう直せば良いのでしょうか?
zipを解凍し元のzipを削除する同じようなスクリプトは問題なく動くので、違いもよく分かりません。

python

1#!/usr/bin/env python3 2# auto_zip.py 3import argparse 4import concurrent.futures 5import pathlib 6import shutil 7 8 9# Lose data. 10def auto_zip_multi_thread(dirs: list[pathlib.Path]) -> None: 11 with concurrent.futures.ThreadPoolExecutor() as executor: 12 future_to_dir = {executor.submit(zip_and_remove_dir, i): i for i in dirs} 13 concurrent.futures.as_completed(future_to_dir) 14 15 16# Work fine and don't lose data. 17def auto_zip(dirs: list[pathlib.Path]) -> None: 18 for i in dirs: 19 zip_and_remove_dir(i) 20 21 22def zip_and_remove_dir(path: pathlib.Path) -> None: 23 shutil.make_archive(path, "zip", root_dir=path.parent, base_dir=path.name) 24 shutil.rmtree(path) 25 26 27def main(): 28 parser = argparse.ArgumentParser() 29 parser.add_argument("-p", "--path") 30 args = parser.parse_args() 31 path = pathlib.Path(args.path) 32 33 dirs = [i for i in path.iterdir() if i.is_dir()] 34 35 auto_zip(dirs) 36 # auto_zip_multi_thread(dirs) 37 38 39if __name__ == "__main__": 40 main() 41
#!/usr/bin/env python3 # auto_unzip.py import argparse import concurrent.futures import os import pathlib import zipfile def auto_unzip_multi_thread(zips: list[pathlib.Path]) -> None: with concurrent.futures.ThreadPoolExecutor() as executor: future_to_zip = {executor.submit(unzip_and_remove, z): z for z in zips} concurrent.futures.as_completed(future_to_zip) def unzip_and_remove(path: pathlib.Path) -> None: with zipfile.ZipFile(path) as existing_zip: existing_zip.extractall(os.path.splitext(path)[0]) os.remove(path) def main(): parser = argparse.ArgumentParser() parser.add_argument("-p", "--path") args = parser.parse_args() path = pathlib.Path(args.path) zip_files = [i for i in path.iterdir() if i.suffix[1:] == "zip"] auto_unzip_multi_thread(zip_files) if __name__ == "__main__": main()

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/02/11 23:06

ありがとうございます。 改めて"make_archive thread safe"で検索すると公式のissueにも挙がってるんですね。
guest

回答1

0

ベストアンサー

make_archive()がスレッドセーフでないのが原因。
代わりに、subprocess.run()内でcd, zipコマンドを呼び出すことで解決。

Python

1def zip_and_remove_dir(path: pathlib.Path) -> None: 2 command = f"cd {str(path.parent)!r} && " \ 3 f"zip -r {str(path.name) + '.zip'!r} {path.name!r}" 4 subprocess.run(command, shell=True, stdout=null) 5 6 shutil.rmtree(path)

投稿2021/02/11 23:07

編集2021/02/12 02:37
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問