質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.46%
Python 3.x

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

Q&A

解決済

3回答

1019閲覧

Python3で関数と平文?で実行した時の処理速度の変化の原因を知りたい

yayakona

総合スコア69

Python 3.x

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

0グッド

0クリップ

投稿2021/10/16 09:56

質問内容

こちらの問題を解いていて、疑問に感じたことがあったため、質問させてください。
https://atcoder.jp/contests/joi2007ho/tasks/joi2007ho_c

関数を使用した場合と使用しなかった場合を比較した時に、
前者のコードの実行時間が8割程度短い結果となりました。

この時、何が原因で処理時間が大きく変化しているかを知りたいです。
確認したいポイントとしては、以下2点になります。

  • 基本的にどんな場合でも、関数を挟んだ方が早いのか
  • それとも、関数化しない場合に、遅くなる処理をしてしまっているのか

よろしくお願いいたします。

関数を使用した場合

python

1from itertools import permutations 2 3def solve(): 4 N = int(input()) 5 points = [tuple(map(int, input().split())) for _ in range(N)] 6 set_points = set(points) 7 ans = 0 8 for (x1, y1), (x2, y2) in permutations(points, 2): 9 dx, dy = x2-x1, y2-y1 10 if (x2-dy, y2+dx) not in set_points: continue 11 if (x1-dy, y1+dx) not in set_points: continue 12 ans = max(ans, dx**2+dy**2) 13 print(ans) 14solve()

https://atcoder.jp/contests/joi2007ho/submissions/26582973

関数を使用しなかった場合

python

1from itertools import permutations 2 3N = int(input()) 4points = [tuple(map(int, input().split())) for _ in range(N)] 5set_points = set(points) 6ans = 0 7for (x1, y1), (x2, y2) in permutations(points, 2): 8 dx, dy = x2-x1, y2-y1 9 if (x2-dy, y2+dx) not in set_points: continue 10 if (x1-dy, y1+dx) not in set_points: continue 11 ans = max(ans, dx**2+dy**2) 12 13print(ans)

https://atcoder.jp/contests/joi2007ho/submissions/26582880

補足情報(FW/ツールのバージョンなど)

Python(3.8.2)

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

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

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

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

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

guest

回答3

0

話の前段

CPythonのGitHubリポジトリには、ベンチマークスクリプトとして var_access_benchmark.py(URL)という物があります。
これは、リリースにおいてパフォーマンス最適化を行った際に、ドキュメントにバージョンごとの推移を提示するために利用しているようです。

計測

※以下、前提として「『__main__上で全て処理する関数を使用しないケース』は変数がglobalにある」とします
(ベンチマークのglobal系はモジュールグローバルを関数内でglobal式で利用しており、Pythonコード上で若干の差異があるのと、内部実装にそこまで詳しくないため)

CPythonのリリースノートでの比較()に掲載されている内容や、
実際に手元でスクリプトを動かした内容を見る限り、特に変数への書き込みに関して、localglobalの比較では一応の差が見られます。

Window上Python3.10での結果。

text

1Variable and attribute read access: 2 5.0 ns read_local 3 6.3 ns read_global 4 5Variable and attribute write access: 6 5.2 ns write_local 7 17.1 ns write_global

処理の増加傾向という観点で見ると、1回あたりのlocal変数への書き込みはglobal変数への書き込みより3倍ほど速い計算になります。
※他にWSL上Python3.9でも実施したがwrite_local,write_globalがそれなりに差がつくことは計測しました

上記の計測をもとにした推測

1処理あたりの時間単位がナノ秒なので、実態としてどうかまでは断定できないですが、
Atcoder問題の後半ケースだとそれなりの処理回数はあると思うので、目立つレベルの差になることはあるのかなとは思います。

投稿2021/10/16 14:08

attakei

総合スコア2738

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

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

yayakona

2021/10/17 04:01

ご回答ありがとうございます。 今回のケースだと最大処理回数が 3000C2で4.5×10^6程度発生する為、 計算上でも0.2秒程度の差になりますね。(書き込みが発生する変数数を5とした時) 私の方でもvar_access_benchmark.pyの確認を行ってみます。 詳しいご回答ありがとうございました。
guest

0

ベストアンサー

関数を介す・介さないの違いはnamespaceの違いなので「localの名前空間へのアクセスの方がglobalの名前空間へのアクセスよりも高速」という理由が考えられます。

Pythonだと、なんか関数を介した方が速いみたいなTipsがあった気がしますが、参考文献も見つからないですし真偽ははっきりしません。

しかしPythonを使っている肌感覚としては、「もしも」上記の理由が真だと言われたら、あぁそうなんだーと納得するくらいあり得そうな話ではあります。

投稿2021/10/16 11:30

YouheiSakurai

総合スコア6142

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

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

yayakona

2021/10/16 11:44

ご回答ありがとうございます。 > 「localの名前空間へのアクセスの方がglobalの名前空間へのアクセスよりも高速」 確か差が出るとしたらこれはありそうですね。 私の方でもこの辺りの情報調べてみます。 ありがとうございます。
Zuishin

2021/10/16 12:37 編集

根拠がなさすぎる回答にベストアンサーがついているので低評価します。 本当に差が出るのかどうかの検証すらなされていません。
YouheiSakurai

2021/10/16 12:59

お役に立てて良かったです。あと一つ思いついたのは、関数にしたほうがインタープリタの処理単位が広くなるといったこともあった気がします。これもヒントくらいになれば幸いです。
guest

0

どうやって実行時間を測ったんでしょうか。
その測り方により、大きくその値が変わります

イマドキのCPUには、キャッシュメモリというものが搭載されており、その中に収まるコードであれば高速で実行されます。
関数という単位にまとめることにより、それがうまくキャッシュに収まることで高速になった、とかなんとか理由付けはできるかと思いますが、
実際のところはどうでしょうか。

投稿2021/10/16 10:17

編集2021/10/16 10:21
y_waiwai

総合スコア87800

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

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

yayakona

2021/10/16 10:39

ご回答有り難うございます。 > どうやって実行時間を測ったんでしょうか。 こちらAtcoderというサイトの問題で、 サイトにコードを投げて実行結果を受ける形式になります。 なので、実行時間に関しては、サイト側で表示されるものを参照しています。 私が見ている実行時間の表示自体は、コードの下に添付しているurlのものです。 キャッシュに収まるか否かで言うとコードサイズからして、 あまり差がないように感じます。
y_waiwai

2021/10/16 10:50

ああ、ならそのATCoderにその実行時間の差異について問い合わせてみてはどうでしょう。 これについていろんなこじつけはできるとは思いますが、実際はどういう理由でそうなるのかってのは誰にもわからないと思いますが。
yayakona

2021/10/16 11:06

大規模データに対する実行結果なので、Atcoder環境特有の挙動ではなく、 Pythonの仕様上の違いと考えるのが素直かなと思っています。 また、実行ごとに大きく処理時間が変化するようであれば環境依存かなと思いますが、 今回のケースでは、同じコードを投げると同じような処理時間で返ってきているそれもないかなと思います。
y_waiwai

2021/10/16 11:09

その処理時時間ってのはあくまでATCoderが出してる値なわけで、それが果たしてあなたのPCでの実行時間と同じだと誰が証明できるんでしょうか。
yayakona

2021/10/16 11:26

何の話でしょうか? 今回の実行時間の差異は、Atcoder側の仕様依存のものではなく、 Pythonの仕様で起きているものだと思っているため、この場で質問させて頂いております。 そう考える根拠は先に述べたとおりで、 それが何故証明云々の話になるのかわかりません。 私の望む回答は得られないように感じるため、 これ以上の返信は控えさせて頂きます。
y_waiwai

2021/10/16 11:41

まあこれが、pythonの仕様ではない、としたらどうしましょうか。 どう思うかってのは人それぞれなんで、べつにそんでいいですけどねえ。
y_waiwai

2021/10/16 11:47

ああ、結局、そう思う、ってはなしでしかないんですねー
Zuishin

2021/10/16 11:48

何をもって関数の方が速いと判断したのか私もわかりません。 誤差じゃないんですか? データ 10 に関しては関数を使用した方が倍近く遅くなっていますが。
yayakona

2021/10/16 12:21

> データ 10 に関しては関数を使用した方が倍近く遅くなっていますが。 関数有り 1603 ms 関数無し 2993 ms に見えていますが、私がおかしいでしょうか。
Zuishin

2021/10/16 12:33

逆に見ていたようです。 つまりここが根拠ということですか?
yayakona

2021/10/16 12:44

根拠は以下2点です。 ・大規模データ7-10において、同様の処理時間の差異が見られた ・複数回実行しても同様の傾向が見られた 不足でしょうか。
Zuishin

2021/10/16 13:05

通常このような差異を調べる場合、少なくとも百回は試行して最大値・最小値・平均値をとります。 「同様」とか「傾向」とかいう言葉では根拠になりません。
Zuishin

2021/10/16 13:08

また「この問題のみの話」ではなく「関数を使う使わないの一般的な話」であるならば、検証用のコードを複数種類作ってローカルでテストできるはずです。
yayakona

2021/10/16 13:11

これは質問であって論文ではありません。 > 少なくとも百回は試行して最大値・最小値・平均値 teratailの規約からこちらを元に質問を行わなければならない根拠をご提示ください。 これ以上の返信は控えさせて頂きます。
Zuishin

2021/10/16 13:16 編集

規約は関係ありません。ふわっとした質問にふわっとしたベストアンサーがついたので、疑問点を書いただけです。個人の感想以上の根拠がないことがわかったので、ただの雑談以上の意味は感じられません。これ以上の無意味な返信は無用です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問