<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Python:對程序做性能分析及計時統計

      1.對整個程序的性能分析

      如果只是想簡單地對整個程序做計算統計,通常使用UNIX下的time命令就足夠了。

      (base) ?  Learn-Python time python someprogram.py       
      python someprogram.py  0.10s user 0.01s system 98% cpu 0.117 total
      

      由于我用的是Mac系統,和Linux系統的輸出可能有不同,不過關鍵都是這三個時間:

      • user: 運行用戶態代碼所花費的時間,也即CPU實際用于執行該進程的時間,其他進程和進程阻塞的時間不計入此數字。

      • system: 在內核中執行系統調用(如I/O調用)所花費的CPU時間。

      • total(Linux下應該是real):即掛鐘時間(wall-clock time),也稱響應時間(response time)、消逝時間(elapsed time),是進程運行開始到結束所有經過的時間,包括了進程使用的時間片和進程阻塞的時間(例如等待I/O完成)。

      請注意,若user + system > total,可能存在多個處理器并行工作;
      若user + system < total,則可能在等待磁盤、網絡或其它設備的響應。

      也就說上面這個程序的掛鐘時間為0.251s,CPU實際用于執行該進程的時間為0.24s,用于系統調用的時間為0.01s。

      再來看看另外一個極端,如果想針對程序的行為產生一份詳細的報告,那么可以使用cProfile模塊:

      (base) ?  Learn-Python python -m cProfile someprogram.py
               7 function calls in 0.071 seconds
      
         Ordered by: standard name
      
         ncalls  tottime  percall  cumtime  percall filename:lineno(function)
              1    0.002    0.002    0.071    0.071 someprogram.py:1(<module>)
              1    0.039    0.039    0.068    0.068 someprogram.py:1(func1)
              1    0.029    0.029    0.029    0.029 someprogram.py:3(<listcomp>)
              1    0.000    0.000    0.001    0.001 someprogram.py:7(func2)
              1    0.000    0.000    0.000    0.000 someprogram.py:9(<listcomp>)
              1    0.000    0.000    0.071    0.071 {built-in method builtins.exec}
              1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
      

      可見我們上述代碼的熱點是在于func1函數。

      這里再多說幾句,這里傳入的-m -cProfile可選參數意為將Python的cPofile模塊做為腳本運行,實際上等價于:

      python /Users/orion-orion/miniforge3/lib/python3.9/cProfile.py someprogram.py
      

      當然,中間那個路徑取決于大家各自的環境。這也就是說我們將some_program.py做為cProfile.py程序的輸入參數,目的就是對其進行性能分析。

      2.對特定代碼段做性能分析

      2.1 分析函數和語句塊

      不過對于做代碼性能分析而言,更常見的情況則處于上述兩個極端情況之間。

      比如,我們可能已經知道了代碼把大部分運行時間都花在幾個某幾個函數上了。要對函數進行性能分析,使用裝飾器就能辦到。示例如下:

      import time
      from functools import wraps
      
      def timethis(func):
          @wraps(func)
          def wrapper(*args, **kwargs):
              start = time.perf_counter()
              r = func(*args, **kwargs)
              end = time.perf_counter()
              print("{}.{} : {}".format(func.__module__, func.__name__, end - start))
              return r
          
          return wrapper
      

      要使用這個裝飾器,只要簡單地將其放在函數定義之前,就能得到對應函數的計時信息了。示例如下:

      @timethis
      def countdown(n):
          while n > 0:
              n -= 1
      
      countdown(10000000)       
      

      控制臺打印輸出:

      __main__.countdown : 0.574160792
      

      請注意,在進行性能統計時,任何得到的結果都是近似值。我們這里使用的函數time.perf_counter()是能夠提供給定平臺上精度最高的計時器,它返回一個秒級的時間值。但是,它計算的仍然是掛鐘時間(墻上時間),這會受到許多不同因素的影響(例如機器當前的負載),且它會將程序等待中斷的sleep(休眠)時間也計算在內。

      如果相對于掛鐘時間,我們更感興趣的是進程時間(包括在內核態和用戶態中所花費的CPU時間),那么可以使用time.process_time()來替代。示例如下:

      def timethis(func):
          @wraps(func)
          def wrapper(*args, **kwargs):
              start = time.process_time()
              r = func(*args, **kwargs)
              end = time.process_time()
              print("{}.{} : {}".format(func.__module__, func.__name__, end - start))
              return r
          
          return wrapper
      

      接下來我們看如何對語句塊進行計算統計,這可以通過定義一個上下文管理器來實現。示例如下:

      from contextlib import contextmanager
      
      @contextmanager
      def timeblock(label):
          start = time.perf_counter()
          try:
              yield
          finally:
              end = time.perf_counter()
              print("{} : {}". format(label, end - start))
      

      下面這個例子演示了這個上下文管理器是如何工作的:

      with timeblock("counting"):
          n = 10000000
          while n > 0:
              n -= 1
      

      控制臺打印輸出如下所示:

      counting : 0.7888195419999999
      

      最后,我們來看一種一勞永逸的方案:在time模塊中的函數之上構建一個更高層的接口來模擬秒表,從而解決對函數、對代碼塊的計時問題。

      import time
      
      class Timer:
          def __init__(self, func=time.perf_counter):
              self.elapsed = 0.0
              self._func = func
              self._start = None
          
          def start(self):
              if self._start is not None:
                  raise RuntimeError("Already started!")
              self._start = self._func()
          
          def stop(self):
              if self._start is None:
                  raise RuntimeError("Not started!")
              end = self._func()
              self.elapsed += end - self._start
              self._start = None
          
          def reset(self):
              self.elapsed = 0.0
          
          @property
          def running(self):
              return self._start is not None
      
          def __enter__(self):
              self.start()
              return self
          
          def __exit__(self, *args):
              self.stop()
      

      這個類定義了一個定時器,可以根據用戶的需要啟動、停止和重置它。Timer類將總的花費時間記錄在elapsed屬性中。下面的實例展示了如何使用這個類:

      t = Timer()
      
      # Use 1: Explicit start/stop
      t.start()
      countdown(1000000)
      t.stop()
      print(t.elapsed)
      # 0.058305625
      
      # Use 2: As a context manager
      with t:
          countdown(1000000)
      print(t.elapsed)
      # 0.11482683300000004
      
      with Timer() as t2:
          countdown(1000000)
      print(t2.elapsed)
      # 0.056095916999999995
      

      如同前面所展示的,由Timer類記錄的時間是掛鐘時間,其中包含了所有的sleeping時間。如果僅想獲取進程的CPU時間(包括在用戶態和內核態中的時間),可以用time.process_time()取代。示例如下:

      t = Timer(time.process_time)
      with t:
          countdown(1000000)
      print(t.elapsed)
      # 0.05993699999999999
      

      2.2 分析單條代碼片段

      如果要對短小的代碼片段做性能統計,timeit模塊會很有幫助。示例如下:

      from timeit import timeit
      
      print(timeit("math.sqrt(2)", "import math"))
      # 0.07840395799999997
      
      print(timeit("sqrt(2)", "from math import sqrt"))
      # 0.05943025000000002
      

      timeit會執行第一個參數中指定的語句一百萬次,然后計算時間。第二個參數是一個配置字符串,在運行測試之前會先執行以設定好環境。如果要修改需要迭代的次數,只需要提供一個number參數即可:

      print(timeit("math.sqrt(2)", "import math", number=10000000))
      # 0.7569702089999999
      
      print(timeit("sqrt(2)", "from math import sqrt", number=10000000))
      # 0.5865757500000002
      

      最后但同樣重要的是,如果打算進行詳細的計時統計分析,請確保先閱讀timetimeit以及其他相關模塊的文檔。這樣才能理解不同系統平臺之間的重要差異以及其他一些缺陷。

      參考

      posted @ 2022-11-27 17:28  orion-orion  閱讀(1108)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 久久精品免视看国产成人| 亚洲高清国产成人精品久久| 国产精品免费看久久久| 国产一区二区在线观看粉嫩| 精品一区二区三区在线成人| 日本另类αv欧美另类aⅴ| 在线观看国产一区亚洲bd | 国产精品区一区第一页| 激情综合网激情五月伊人| 久久99精品久久久久麻豆| 亚洲国产高清av网站| 国产性生大片免费观看性| 亚洲一区二区三区丝袜| 国产欧美亚洲精品a第一页| 日韩精品一区二区三免费| 亚洲第一福利网站在线观看| 国产乱码精品一区二区三| 亚洲激情av一区二区三区| 亚洲男人的天堂久久香蕉| 国产亚洲精品日韩av在| 中文字幕国产精品综合| av深夜免费在线观看| 亚洲人成网网址在线看| 国产精品麻豆成人av网| 99在线国内在线视频22| jizz国产免费观看| 欧美综合天天夜夜久久| 婷婷五月综合丁香在线| 亚洲精品天堂在线观看| 日韩A人毛片精品无人区乱码| 东京道一本热中文字幕| 亚欧美闷骚院| 自拍偷拍第一区二区三区| 色九月亚洲综合网| 久久精品国产中文字幕| 日韩中文字幕综合第二页| 久久成人国产精品免费软件| 国产边打电话边被躁视频| 曲阜市| 水蜜桃精品综合视频在线| 宾馆人妻4P互换视频|