15

1 つのプロセッサで実行されるスクリプト (およびマルチスレッドなし) で Python 組み込みプロファイラーを使用する

time python -m cProfile myscript.py

プロファイラーによって報告される CPU 時間は 345.710 CPU 秒です。

24184348 function calls (24183732 primitive calls) in 345.710 CPU seconds

そして、実際のuserおよびsys時間は次のとおりです。

real    5m45.926s
user    1m59.340s
sys     0m39.452s

ご覧のとおり、CPU 時間はほぼリアルタイムです (345.710 = 5m45.710s)。

この結果を踏まえて、プロファイラーによって報告された CPU 時間には、他のプロセスによって使用されたタイム スライスとプロセスがブロックされた時間が含まれていると想定できますか? つまり、プロファイラーの CPU 時間はプロセス時間 (user+sys) ではなく、 time(1) の出力で「real」、「user」、および「sys」は何を意味するかで説明されているウォール クロック時間です。

よろしくお願いします

4

3 に答える 3

17

これは、実際のユーザー、およびシステムのタイミングの意味に関する詳細に美しく答えます。引用するには:

  • 「Real」は実時間です。つまり、通話の開始から終了までの時間です。これは、他のプロセスによって使用されるタイム スライスと、プロセスがブロックされている時間 (たとえば、I/O の完了を待機している場合) を含むすべての経過時間です。

  • 「ユーザー」は、プロセス内のユーザー モード コード (カーネルの外部) で費やされた CPU 時間の量です。これは、プロセスの実行に使用される実際の CPU 時間のみです。他のプロセスとプロセスがブロックされた時間は、この数値にはカウントされません。

  • 「Sys」は、プロセス内のカーネルで費やされた CPU 時間の量です。これは、ユーザー空間でまだ実行されているライブラリ コードとは対照的に、カーネル内のシステム コールで費やされた CPU 時間を実行することを意味します。「ユーザー」と同様に、これはプロセスによって使用される CPU 時間のみです。

上記の説明から、User+Sys 時間は CPU 秒に等しいように見えます。代わりに、「リアルタイム」に近くなります。変!

それには正当な説明があります。「ユーザー」時間には、プロセス内の I/O 操作に費やされた CPU 秒は含まれません。メモリ内のユーザー モード コードに費やされた CPU 時間を測定するだけです。経験則は次のとおりです。

リアルタイム = ユーザー + システム + I/O 時間 + インタープリターの起動時間 + バイトコードのコンパイル時間

これを検証するために、私はurllib2.urlopen(urllib2.Request(url))集中的な I/O を実行する呼び出しを行いました。結果は次のとおりです。

         100792 function calls (98867 primitive calls) in 2.076 CPU seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
      512    0.719    0.001    0.719    0.001 {method 'recv' of '_socket.socket' objects}
        1    0.464    0.464    0.473    0.473 {_socket.getaddrinfo}
        1    0.352    0.352    0.352    0.352 <string>:1(connect)
        1    0.248    0.248    0.348    0.348 common_functions.py:1(<module>)
        1    0.022    0.022    0.075    0.075 __init__.py:2(<module>)
        1    0.017    0.017    0.030    0.030 urllib.py:1442(getproxies_macosx_sysconf)
   330/67    0.012    0.000    0.031    0.000 sre_parse.py:385(_parse)


real    0m2.255s
user    0m0.352s
sys 0m0.093s

ここでは、2.076-(0.352+0.093)、つまり 1.631 CPU 秒が I/O 操作 (主に_socket.socket_socket.getaddrinfo) で消費されました。残りの 2.255 ~ 2.076 時間は、コードのコールド スタートに費やされました。

それが役に立ったことを願っています。

更新: 複数の CPU が並行して動作するマルチコア システムでは、ケースが少し異なります。cProfile によって報告される合計 CPU 秒は、すべての CPU が個別に費やした時間の合計です。例: 2 コア システムで、1 つの CPU が 10 秒間動作する場合。並行して、別の CPU が 15 秒間動作します。報告される合計 CPU 秒は 25 秒です。実際の経過時間はわずか15秒かもしれませんが。したがって、CPU 時間は、マルチコア システムではリアルタイムよりも長くなる場合があります。CPUが並行して動作しているため

于 2012-03-02T13:54:00.227 に答える
7

Python プロファイラーはデフォルトで壁時間を測定しますが、カスタム タイマー関数を使用して CPU 時間を測定するようにすることもできます。以下は Linux では機能しますが、Windows では機能しません (Windows でtime.clock壁時間を測定するため)。

import cProfile
import time


def idleWait():
    time.sleep(10)

def busyWait():
    t = time.time() + 10
    while time.time() < t: pass

def target():
    idleWait()
    busyWait()


print "Wall time:"
p = cProfile.Profile()
p.runcall(target)
p.print_stats()

print "CPU time:"
p = cProfile.Profile(time.clock)
p.runcall(target)
p.print_stats()

最初のプロファイル実行では 20 秒が経過し、その約半分がtime.sleep. 2 番目は 10 秒が経過したことを示していtime.sleepます。

于 2013-08-02T09:03:45.993 に答える