私はTomorrowというライブラリを使用していますが、Async関数の呼び出しを可能にするために標準ライブラリのThreadPoolExecutorを使用しています。なぜ、1人のワーカーを持つThreadPoolExecutorは通常の実行よりも高速ですか?
デコレータを呼び出す@tomorrow.threads(1)
は、1人の作業者でThreadPoolExecutorをスピンアップします。
質問
- なぜそれが(例えば通常)であるとして、それを呼び出す上
1 thread worker
を使用して機能を実行する方が速いですか? 10 thread workers
と同じコードを1の代わりに実行するのが遅いのはなぜですか?
デモコード
輸入は
def openSync(path: str):
for row in open(path):
for _ in row:
pass
@tomorrow.threads(1)
def openAsync1(path: str):
openSync(path)
@tomorrow.threads(10)
def openAsync10(path: str):
openSync(path)
def openAll(paths: list):
def do(func: callable)->float:
t = time.time()
[func(p) for p in paths]
t = time.time() - t
return t
print(do(openSync))
print(do(openAsync1))
print(do(openAsync10))
openAll(glob.glob("data/*"))
注意を除外:data
フォルダには18個のファイル、ランダムなテキストの各700行が含まれています。
出力
0労働者: 0.0120 秒
1労働者: 0.0009 秒
10労働者: 0.0535 秒私がきたもの
テストしました
- 私は複数のdusin回以上、別のプログラムをバックグラウンドで実行していました(昨日、そして今日カップルを走らせました)。数字はofcに変わりますが、順序は常に同じです。 (すなわち、1が最も速く、次いで0が10)。
- 私はまた、要因としてキャッシングを排除するために、実行順序を変更してみました。
- は、他のすべての順列と比較(1 0、次いで、その後、10最速で)異なる順序に、
1
、順10
にNone
結果を実行することが判明しました。結果は、do
の呼び出しが最後に実行されたときは、最初に実行されたか、その代わりに途中で実行されたよりもかなり遅いことを示します。 (@Dunesから溶液を受信した後)
- は、他のすべての順列と比較(1 0、次いで、その後、10最速で)異なる順序に、
結果
0労働者: 0.0122 秒
1ワーカー: 0。0214 秒
10労働者: 0.0296 秒
正確なパフォーマンス統計に近いものは、サンプルサイズが小さすぎます。また、ファイル操作などのテストでは、(オペレーティングシステム内の)キャッシングの影響を考慮する必要があります。 –
@DarkFalcon私は、複数のdusin回以上のコードを実行しました。さまざまなプログラムがバックグラウンドで実行されています(昨日、そして今日カップルを走らせました)。数字はofcに変わりますが、順序は常に同じです。 私はまた、実行の順番を入れ替えようとしました。 'do'コールを動かす。まだ同じ。 – Olian04
テストが正しく表示されません。つまり、非同期バリアントは、テストを終了する前にすべての作業が終了するまで待つ必要はありません。つまり、すべてのワーカースレッドをセットアップするのにかかる時間と、スレッドが作業を完了するまでに要する時間ではありません。 – Dunes