`shutil.copytree` を高速化します!
shutil.copytree の高速化について議論する
ここに書いてください
これは に関するディスカッションです。https://discuss.python.org/t/speed-up-shutil-copytree/62078 を参照してください。何かアイデアがあれば、ぜひ送ってください!
背景
shutil は Python の非常に便利なモジュールです。これは github で見つけることができます: https://github.com/python/cpython/blob/master/Lib/shutil.py
shutil.copytree は、フォルダーを別のフォルダーにコピーする関数です。
この関数では、_copytree 関数を呼び出してコピーします。
_copytree は何をしますか?
- 指定されたファイル/ディレクトリを無視します。
- 宛先ディレクトリを作成しています。
- シンボリック リンクの処理中にファイルまたはディレクトリをコピーします。
- 発生したエラー (権限の問題など) を収集し、最終的に発生させます。
- ソース ディレクトリのメタデータを宛先ディレクトリに複製します。
問題点
ファイル数が多い場合やファイルサイズが大きい場合、_copytree の速度はあまり速くありません。
ここでテストします:
import os import shutil os.mkdir('test') os.mkdir('test/source') def bench_mark(func, *args): import time start = time.time() func(*args) end = time.time() print(f'{func.__name__} takes {end - start} seconds') return end - start # write in 3000 files def write_in_5000_files(): for i in range(5000): with open(f'test/source/{i}.txt', 'w') as f: f.write('Hello World' + os.urandom(24).hex()) f.close() bench_mark(write_in_5000_files) def copy(): shutil.copytree('test/source', 'test/destination') bench_mark(copy)
結果は次のとおりです:
write_in_5000_files には 4.084963083267212 秒かかります
コピーには 27.12768316268921 秒かかります
私がやったこと
マルチスレッド化
コピー処理を高速化するためにマルチスレッドを使用しています。そして、関数 _copytree_single_threaded の名前を変更し、新しい関数 _copytree_multithreaded を追加します。以下は copytree_multithreaded です:
def _copytree_multithreaded(src, dst, symlinks=False, ignore=None, copy_function=shutil.copy2, ignore_dangling_symlinks=False, dirs_exist_ok=False, max_workers=4): """Recursively copy a directory tree using multiple threads.""" sys.audit("shutil.copytree", src, dst) # get the entries to copy entries = list(os.scandir(src)) # make the pool with ThreadPoolExecutor(max_workers=max_workers) as executor: # submit the tasks futures = [ executor.submit(_copytree_single_threaded, entries=[entry], src=src, dst=dst, symlinks=symlinks, ignore=ignore, copy_function=copy_function, ignore_dangling_symlinks=ignore_dangling_symlinks, dirs_exist_ok=dirs_exist_ok) for entry in entries ] # wait for the tasks for future in as_completed(futures): try: future.result() except Exception as e: print(f"Failed to copy: {e}") raise
マルチスレッドを使用するかどうかの判断を追加します。
if len(entries) >= 100 or sum(os.path.getsize(entry.path) for entry in entries) >= 100*1024*1024: # multithreaded version return _copytree_multithreaded(src, dst, symlinks=symlinks, ignore=ignore, copy_function=copy_function, ignore_dangling_symlinks=ignore_dangling_symlinks, dirs_exist_ok=dirs_exist_ok) else: # single threaded version return _copytree_single_threaded(entries=entries, src=src, dst=dst, symlinks=symlinks, ignore=ignore, copy_function=copy_function, ignore_dangling_symlinks=ignore_dangling_symlinks, dirs_exist_ok=dirs_exist_ok)
テスト
ソースフォルダーに 50000 個のファイルを書き込みます。ベンチマーク:
def bench_mark(func, *args): import time start = time.perf_counter() func(*args) end = time.perf_counter() print(f"{func.__name__} costs {end - start}s")
次のように記入してください:
import os os.mkdir("Test") os.mkdir("Test/source") # write in 50000 files def write_in_file(): for i in range(50000): with open(f"Test/source/{i}.txt", 'w') as f: f.write(f"{i}") f.close()
2 つの比較:
def copy1(): import shutil shutil.copytree('test/source', 'test/destination1') def copy2(): import my_shutil my_shutil.copytree('test/source', 'test/destination2')
- 「my_shutil」は私の修正版 shutil です。
コピー 1 のコストは 173.04780609999943 秒
copy2 のコストは 155.81321870000102s
copy2 は copy1 よりもはるかに高速です。何度も実行できます。
メリットとデメリット
マルチスレッドを使用すると、コピー処理を高速化できます。ただし、メモリ使用量が増加します。ただし、コード内のマルチスレッドを書き直す必要はありません。
非同期
「バリー・スコット」に感謝します。私は彼/彼女の提案に従います:
非同期 I/O を使用すると、オーバーヘッドを減らして同じ改善が得られる可能性があります。
私は次のコードを書きます:
import os import shutil import asyncio from concurrent.futures import ThreadPoolExecutor import time # create directory def create_target_directory(dst): os.makedirs(dst, exist_ok=True) # copy 1 file async def copy_file_async(src, dst): loop = asyncio.get_event_loop() await loop.run_in_executor(None, shutil.copy2, src, dst) # copy directory async def copy_directory_async(src, dst, symlinks=False, ignore=None, dirs_exist_ok=False): entries = os.scandir(src) create_target_directory(dst) tasks = [] for entry in entries: src_path = entry.path dst_path = os.path.join(dst, entry.name) if entry.is_dir(follow_symlinks=not symlinks): tasks.append(copy_directory_async(src_path, dst_path, symlinks, ignore, dirs_exist_ok)) else: tasks.append(copy_file_async(src_path, dst_path)) await asyncio.gather(*tasks) # choose copy method def choose_copy_method(entries, src, dst, **kwargs): if len(entries) >= 100 or sum(os.path.getsize(entry.path) for entry in entries) >= 100 * 1024 * 1024: # async version asyncio.run(copy_directory_async(src, dst, **kwargs)) else: # single thread version shutil.copytree(src, dst, **kwargs) # test function def bench_mark(func, *args): start = time.perf_counter() func(*args) end = time.perf_counter() print(f"{func.__name__} costs {end - start:.2f}s") # write in 50000 files def write_in_50000_files(): for i in range(50000): with open(f"Test/source/{i}.txt", 'w') as f: f.write(f"{i}") def main(): os.makedirs('Test/source', exist_ok=True) write_in_50000_files() # 单线程复制 def copy1(): shutil.copytree('Test/source', 'Test/destination1') def copy2(): shutil.copytree('Test/source', 'Test/destination2') # async def copy3(): entries = list(os.scandir('Test/source')) choose_copy_method(entries, 'Test/source', 'Test/destination3') bench_mark(copy1) bench_mark(copy2) bench_mark(copy3) shutil.rmtree('Test') if __name__ == "__main__": main()
出力:
copy1 のコストは 187.21 秒
copy2 のコストは 244.33 秒
copy3 のコストは 111.27 秒
非同期バージョンはシングルスレッドバージョンよりも高速であることがわかります。ただし、シングル スレッド バージョンはマルチスレッド バージョンよりも高速です。 (私のテスト環境があまり良くないかもしれません。試して結果を私に返信して送ってください)
バリー・スコット、ありがとう!
メリットとデメリット
非同期は良い選択です。しかし、完璧な解決策はありません。何か問題が見つかった場合は、返信として私に送ってください。
終わり
python.org でディスカッションを書くのはこれが初めてです。何か問題がございましたら、お知らせください。ありがとうございます。
私の Github: https://github.com/mengqinyuan
私の開発者: https://dev.to/mengqinyuan
以上が`shutil.copytree` を高速化します!の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undress AI Tool
脱衣画像を無料で

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

Quantum Machine Learning(QML)を開始するには、優先ツールがPythonであり、Pennylane、Qiskit、Tensorflowquantum、Pytorchquantumなどのライブラリをインストールする必要があります。次に、Pennylaneを使用して量子ニューラルネットワークを構築するなど、例を実行してプロセスに慣れます。次に、データセットの準備、データエンコード、パラメトリック量子回路の構築、古典的なオプティマイザートレーニングなどの手順に従ってモデルを実装します。実際の戦闘では、最初から複雑なモデルを追求したり、ハードウェアの制限に注意を払ったり、ハイブリッドモデル構造を採用したり、開発をフォローアップするための最新のドキュメントと公式文書を継続的に参照することを避ける必要があります。

この記事では、いくつかのトップPython「完成した」プロジェクトWebサイトと、高レベルの「大ヒット作「学習リソースポータル」が選択されています。開発のインスピレーション、観察、学習のマスターレベルのソースコードを探している場合でも、実用的な機能を体系的に改善している場合でも、これらのプラットフォームは見逃せず、Pythonマスターに迅速に成長するのに役立ちます。

subprocess.run()を使用して、シェルコマンドを安全に実行し、出力をキャプチャします。注入リスクを避けるために、リストのパラメーターを渡すことをお勧めします。 2。シェル特性が必要な場合は、シェル= trueを設定できますが、コマンドインジェクションに注意してください。 3. subprocess.popenを使用して、リアルタイム出力処理を実現します。 4。Check = COMMATが失敗したときに例外をスローするためにtrueを設定します。 5.単純なシナリオで直接チェーンを呼び出して出力を取得できます。 os.system()または非推奨モジュールの使用を避けるために、日常生活の中でsubprocess.run()を優先する必要があります。上記の方法は、Pythonでシェルコマンドを実行するコアの使用を上書きします。

Seabornのジョイントプロットを使用して、2つの変数間の関係と分布をすばやく視覚化します。 2。基本的な散布図は、sns.jointplot(data = tips、x = "total_bill"、y = "tip"、dind = "scatter")によって実装され、中心は散布図であり、ヒストグラムは上部と右側と右側に表示されます。 3.回帰線と密度情報をdind = "reg"に追加し、marminal_kwsを組み合わせてエッジプロットスタイルを設定します。 4。データ量が大きい場合は、「ヘックス」を使用することをお勧めします。

Python Web Crawlersをマスターするには、3つのコアステップを把握する必要があります。1。リクエストを使用してリクエストを開始し、メソッドを取得してWebページのコンテンツを取得し、ヘッダーの設定に注意を払い、例外を処理し、robots.txtを遵守します。 2。美しいソープまたはXPathを使用してデータを抽出します。前者は単純な解析に適していますが、後者はより柔軟で複雑な構造に適しています。 3.セレンを使用して、動的読み込みコンテンツのブラウザ操作をシミュレートします。速度は遅いですが、複雑なページに対処できます。また、効率を向上させるために、WebサイトAPIインターフェイスを見つけることもできます。

httpx.asyncclientを使用して、非同期httpリクエストを効率的に開始します。 1.基本的なGETリクエストは、asyncwithを介してクライアントを管理し、awaitclient.getを使用して非ブロッキングリクエストを開始します。 2。asyncio.gatherを組み合わせてasyncio.gatherを組み合わせると、パフォーマンスが大幅に向上する可能性があり、合計時間は最も遅いリクエストに等しくなります。 3.カスタムヘッダー、認証、base_url、タイムアウト設定をサポートします。 4。投稿リクエストを送信してJSONデータを伝達できます。 5.同期非同期コードの混合を避けるために注意してください。プロキシサポートは、クローラーやAPI集約、その他のシナリオに適したバックエンド互換性に注意を払う必要があります。

文字列リストは、 '' .join(words)などのJoIn()メソッドとマージして、「Helloworldfrompython」を取得できます。 2。NUMBERリストは、参加する前にMAP(STR、数字)または[STR(x)forxinNumbers]を備えた文字列に変換する必要があります。 3.任意のタイプリストは、デバッグに適したブラケットと引用符のある文字列に直接変換できます。 4。カスタム形式は、 '|' .join(f "[{item}]" foriteminitems)output "[a] | [などのjoin()と組み合わせたジェネレーター式によって実装できます。

Pyodbcのインストール:Pipinstallpyodbcコマンドを使用してライブラリをインストールします。 2.接続sqlserver:pyodbc.connect()メソッドを介して、ドライバー、サーバー、データベース、uid/pwdまたはtrusted_connectionを含む接続文字列を使用し、それぞれSQL認証またはWindows認証をサポートします。 3.インストールされているドライバーを確認します:pyodbc.drivers()を実行し、「sqlserver」を含むドライバー名をフィルタリングして、「sqlserverのodbcdriver17」などの正しいドライバー名が使用されるようにします。 4.接続文字列の重要なパラメーター
