PythonのMatlabのticおよびtoc関数に相当するものは何ですか?


112

PythonのMatlabのticおよびtoc関数に相当するものは何ですか?


7
あなたが本当に直接対応をしたい場合は、単に呼び出すtic = time.time()toc = time.time()、その後、print toc-tic, 'sec Elapsed'人々は以下の言ったように、しかし、timeitより堅牢です。
Joe Kington、

:私は、例えば次のように)timeit.default_timer(と一緒にJoeKingtonのアプローチ@使用して、より良い結果を得るように見える tic = timeit.default_timer(); (U,S,V) = np.linalg.svd(A); toc = timeit.default_timer()、それからprint toc-tic
littleO 16

1
ライブラリpytictocは最もわかりやすく、構文は以下のttictocよりも少しすっきりしています。pypi.org/project/pytictoc
FlorianH

回答:


172

timeitThiefMasterが言及したこととは別に、それを行う簡単な方法は(インポートした後time)です:

t = time.time()
# do stuff
elapsed = time.time() - t

使用したいヘルパークラスがあります。

class Timer(object):
    def __init__(self, name=None):
        self.name = name

    def __enter__(self):
        self.tstart = time.time()

    def __exit__(self, type, value, traceback):
        if self.name:
            print('[%s]' % self.name,)
        print('Elapsed: %s' % (time.time() - self.tstart))

コンテキストマネージャとして使用できます。

with Timer('foo_stuff'):
   # do some foo
   # do some stuff

時々、私はこのテクニックがより便利timeitだと思います-それはすべてあなたが測定したいものに依存します。


25
@eat:私は敬意を払いません。人々はunix timeコマンドを使用してプログラムのランタイムを永遠に測定してきましたが、この方法はこれをPythonコード内で複製します。仕事に適したツールである限り、問題はありません。timeit常にそうであるとは限りません。プロファイラーは、ほとんどのニーズに対してはるかにヘビーウェイトのソリューションです
Eli Bendersky

4
最後の行については、私はお勧めしprint 'Elapsed: %.2f seconds % (time.time() - self.tstart)'ます。%.2fなしでは理解するのが難しいです。素晴らしいアイデアをありがとう。
CanKavaklıoğlu2013年

4
これは一見非常に便利に見えますが、実際には、時間をかけたいコードブロックをインデントする必要があります。これは、コードブロックの長さと選択したエディターによっては非常に不便な場合があります。入れ子にした場合でも正しく動作するエレガントなソリューションです。
Stefan

1
elapsed = t - time.time()代わりに欲しいと思いますelapsed = time.time() - t。後者では経過はマイナスになります。この変更を編集として提案しました。
rysqui

3
@rysqui- 現在の時刻は常に前の時刻よりも大きい数ではありませんか?それがelapsed = time.time() - t常にプラスの価値を生み出す形だと思います。
スコットスミス

32

Matlabからpythonに移行したときも同じ質問がありました。このスレッドの助けを借りて、Matlab と関数の正確な類似物を構築することができました。スクリプトの上部に次のコードを挿入するだけです。tic()toc()

import time

def TicTocGenerator():
    # Generator that returns time differences
    ti = 0           # initial time
    tf = time.time() # final time
    while True:
        ti = tf
        tf = time.time()
        yield tf-ti # returns the time difference

TicToc = TicTocGenerator() # create an instance of the TicTocGen generator

# This will be the main function through which we define both tic() and toc()
def toc(tempBool=True):
    # Prints the time difference yielded by generator instance TicToc
    tempTimeInterval = next(TicToc)
    if tempBool:
        print( "Elapsed time: %f seconds.\n" %tempTimeInterval )

def tic():
    # Records a time in TicToc, marks the beginning of a time interval
    toc(False)

それでおしまい!これで、Matlab tic()toc()同様に、完全に使用する準備が整いました。例えば

tic()

time.sleep(5)

toc() # returns "Elapsed time: 5.00 seconds."

実際、これは組み込みのMatlab関数よりも用途が広いです。ここでは、の別のインスタンスを作成TicTocGeneratorして、複数の操作を追跡したり、別のタイミングで計測したりできます。たとえば、スクリプトのタイミングを計っているときに、スクリプト全体と同様に、スクリプトの各部分を別々に計時できるようになりました。(具体例を挙げます)

TicToc2 = TicTocGenerator() # create another instance of the TicTocGen generator

def toc2(tempBool=True):
    # Prints the time difference yielded by generator instance TicToc2
    tempTimeInterval = next(TicToc2)
    if tempBool:
    print( "Elapsed time 2: %f seconds.\n" %tempTimeInterval )

def tic2():
    # Records a time in TicToc2, marks the beginning of a time interval
    toc2(False)

これで、2つの別々の時間を計測できるはずです。次の例では、スクリプト全体とスクリプトの部分を別々に計測します。

tic()

time.sleep(5)

tic2()

time.sleep(3)

toc2() # returns "Elapsed time 2: 5.00 seconds."

toc() # returns "Elapsed time: 8.00 seconds."

実際には、tic()毎回使用する必要はありません。あなたが時間を計りたい一連のコマンドを持っているなら、あなたは書くことができます

tic()

time.sleep(1)

toc() # returns "Elapsed time: 1.00 seconds."

time.sleep(2)

toc() # returns "Elapsed time: 2.00 seconds."

time.sleep(3)

toc() # returns "Elapsed time: 3.00 seconds."

# and so on...

これがお役に立てば幸いです。


22

ticとtocの絶対的な最高の類似物は、単純にそれらをpythonで定義することです。

def tic():
    #Homemade version of matlab tic and toc functions
    import time
    global startTime_for_tictoc
    startTime_for_tictoc = time.time()

def toc():
    import time
    if 'startTime_for_tictoc' in globals():
        print "Elapsed time is " + str(time.time() - startTime_for_tictoc) + " seconds."
    else:
        print "Toc: start time not set"

その後、次のように使用できます。

tic()
# do stuff
toc()

6
これは、Matlabがサポートするticand のネストされた使用の場合、正しく動作しませんtoc。もう少し高度なものが必要になります。
Stefan

2
基本的なタイミングが必要なときに、自分のコードに同様の関数を実装しました。ただし、import timeかなり時間がかかる可能性があるため、両方の機能の外側を削除します。
Bas Swinckels 2013年

この手法の使用を主張し、ネストされたtic / tocを処理する必要がある場合は、グローバルをリストにticして、そこにプッシュしてtocポップします。
Ahmed Fasih 2016

1
また、私はその別の場所で読むtimeit.default_timer()よりも優れているtime.time()ので、time.clock()多くのOSに応じて、適切であるかもしれない
ミゲル・

@AhmedFasihこれが私の答えですが、さらに改善できる点があります。
antonimmo

15

通常、IPythonの%time%timeit%prunおよび%lprun(1がいる場合line_profilerインストールは)非常によく私のプロファイリングのニーズを満たします。ただし、tic-toc対話型で、つまりユーザーがGUIでマウスを動かして計算をプロファイリングしようとしたときに、のような機能のユースケースが発生しました。インタラクティブにテストしている間、ソース内ticのsをスパミングtocすることが、ボトルネックを明らかにする最も早い方法だと感じました。私はEli BenderskyのTimerクラスに行きましたが、コードのインデントを変更する必要があり、一部のエディターでは不便で、バージョン管理システムを混乱させるため、完全には満足していませんでした。さらに、異なる関数のポイント間の時間を測定する必要がある場合があります。これは、withステートメント。多くのPythonの巧妙さを試した後、私が最も効果的に機能することがわかったシンプルなソリューションを次に示します。

from time import time
_tstart_stack = []

def tic():
    _tstart_stack.append(time())

def toc(fmt="Elapsed: %s s"):
    print fmt % (time() - _tstart_stack.pop())

これはスタックの開始時間をプッシュすることで機能するため、ticsとtocsの複数のレベルで正しく機能します。また、tocステートメントのフォーマット文字列を変更して、EliのTimerクラスについて気に入った追加情報を表示することもできます。

どういうわけか、私は純粋なPython実装のオーバーヘッドに関心を持ったので、C拡張モジュールもテストしました。

#include <Python.h>
#include <mach/mach_time.h>
#define MAXDEPTH 100

uint64_t start[MAXDEPTH];
int lvl=0;

static PyObject* tic(PyObject *self, PyObject *args) {
    start[lvl++] = mach_absolute_time();
    Py_RETURN_NONE;
}

static PyObject* toc(PyObject *self, PyObject *args) {
return PyFloat_FromDouble(
        (double)(mach_absolute_time() - start[--lvl]) / 1000000000L);
}

static PyObject* res(PyObject *self, PyObject *args) {
    return tic(NULL, NULL), toc(NULL, NULL);
}

static PyMethodDef methods[] = {
    {"tic", tic, METH_NOARGS, "Start timer"},
    {"toc", toc, METH_NOARGS, "Stop timer"},
    {"res", res, METH_NOARGS, "Test timer resolution"},
    {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC
inittictoc(void) {
    Py_InitModule("tictoc", methods);
}

これはMacOSX用でありlvl、簡潔にするために範囲外かどうかを確認するコードは省略しています。一方でtictoc.res()私のシステム上の利回りは約50ナノ秒の解像度を、私は任意のPythonの文を測定するジッタが(とはるかにIPythonから使用する場合)マイクロ秒の範囲で、容易であることがわかりました。この時点で、Python実装のオーバーヘッドは無視できる程度になるため、C実装と同じ信頼度で使用できます。

tic-toc-approachの実用性は、実行に10マイクロ秒以上かかるコードブロックに実質的に限定されていることがわかりました。その下でtimeitは、忠実な測定値を得るために、inのような平均化戦略が必要です。


1
非常にエレガントな@Stefan-これがそれほど低い評価であるとは信じられません。ありがとう!
2016年

10

tictocから使用できますttictoc。でインストール

pip install ttictoc

次のようにスクリプトにインポートするだけです

from ttictoc import tic,toc
tic()
# Some code
print(toc())

8

ネストされたtic tocsを実現するためのモジュール[tictoc.py]を作成しました。これはMatlabが行うことです。

from time import time

tics = []

def tic():
    tics.append(time())

def toc():
    if len(tics)==0:
        return None
    else:
        return time()-tics.pop()

そしてそれはこのように機能します:

from tictoc import tic, toc

# This keeps track of the whole process
tic()

# Timing a small portion of code (maybe a loop)
tic()

# -- Nested code here --

# End
toc()  # This returns the elapse time (in seconds) since the last invocation of tic()
toc()  # This does the same for the first tic()

お役に立てば幸いです。


MATLABからのtic / tocの素晴らしい複製!
マット

1
(AFAIK)モジュールはシングルトンのように動作するため、これを複数のモジュールで同時に使用すると、期待どおりに動作しない可能性があることを警告します。
antonimmo 2017年

3

timeitモジュールを見てください。実際には同等ではありませんが、時間を計るコードが関数内にある場合は、簡単に使用できます。


はい、timeitベンチマークに最適です。単一の関数である必要はありません。複雑なステートメントを任意に渡すことができます。

10
さて、文字列として非常に単純な関数呼び出しではないコードを渡すことは非常に醜いです。
ThiefMaster、2011年


1

これはラッパーを使用して行うこともできます。時間を保つための非常に一般的な方法。

このコード例のラッパーは関数をラップし、関数の実行に必要な時間を出力します。

def timethis(f):
    import time

    def wrapped(*args, **kwargs):
        start = time.time()
        r = f(*args, **kwargs)
        print "Executing {0} took {1} seconds".format(f.func_name,  time.time()-start)
        return r
    return wrapped

@timethis
def thistakestime():
    for x in range(10000000):
        pass

thistakestime()

ラッパー関数timethisはデコレーターと呼ばれます。もう少し詳細な説明は、こちら:medium.com/pythonhive/…–
Mircea

1

@Eli Benderskyの回答を少し変更して、俳優を使用しました __init__()し、デストラクタを__del__()、それが元のコードをインデントすることなく、より便利に使用できるように、タイミングを行うには:

class Timer(object):
    def __init__(self, name=None):
        self.name = name
        self.tstart = time.time()

    def __del__(self):
        if self.name:
            print '%s elapsed: %.2fs' % (self.name, time.time() - self.tstart)
        else:
            print 'Elapsed: %.2fs' % (time.time() - self.tstart)

使用するには、単純にTimer( "blahblah")をローカルスコープの先頭に置きます。経過時間はスコープの最後に出力されます:

for i in xrange(5):
    timer = Timer("eigh()")
    x = numpy.random.random((4000,4000));
    x = (x+x.T)/2
    numpy.linalg.eigh(x)
    print i+1
timer = None

それは印刷します:

1
eigh() elapsed: 10.13s
2
eigh() elapsed: 9.74s
3
eigh() elapsed: 10.70s
4
eigh() elapsed: 10.25s
5
eigh() elapsed: 11.28s

3
この実装の問題はtimerforループの後に他のコードが続く場合、最後の呼び出しの後に削除されないという事実です。最後のタイマー値を取得するtimerには、forループを介して、たとえばを削除または上書きする必要がありますtimer = None
bastelflp

1
@bastelflp私はあなたが何を言っているのかを誤解していることに気づきました...あなたの提案は現在コードに組み込まれています。ありがとう。
Shaohua Li

1

Python 3 に対するEliの回答の更新:

class Timer(object):
    def __init__(self, name=None, filename=None):
        self.name = name
        self.filename = filename

    def __enter__(self):
        self.tstart = time.time()

    def __exit__(self, type, value, traceback):
        message = 'Elapsed: %.2f seconds' % (time.time() - self.tstart)
        if self.name:
            message = '[%s] ' % self.name + message
        print(message)
        if self.filename:
            with open(self.filename,'a') as file:
                print(str(datetime.datetime.now())+": ",message,file=file)

Eliと同じように、コンテキストマネージャーとして使用できます。

import time 
with Timer('Count'):
    for i in range(0,10_000_000):
        pass

出力:

[Count] Elapsed: 0.27 seconds

また、報告された時間の単位(秒)を出力し、Canの提案に従って桁数をトリミングするように更新しました。また、ログファイルに追加することもできます。ロギング機能を使用するには、datetimeをインポートする必要があります。

import time
import datetime 
with Timer('Count', 'log.txt'):    
    for i in range(0,10_000_000):
        pass

0

ステファンとアントニモの答えに基づいて、私は結局

def Tictoc():
    start_stack = []
    start_named = {}

    def tic(name=None):
        if name is None:
            start_stack.append(time())
        else:
            start_named[name] = time()

    def toc(name=None):
        if name is None:
            start = start_stack.pop()
        else:
            start = start_named.pop(name)
        elapsed = time() - start
        return elapsed
    return tic, toc

utils.py、モジュール、およびIはAでそれを使用します

from utils import Tictoc
tic, toc = Tictoc()

こちらです

  • あなたは単にを使用してtic()toc()Matlabのようにそれらをネストすることができます
  • または、それらに名前を付けることができます:tic(1)toc(1)またはtic('very-important-block')toc('very-important-block')および異なる名前のタイマーは干渉しません
  • この方法でそれらをインポートすると、それを使用するモジュール間の干渉が防止されます。

(ここでtocは経過時間を出力しませんが、それを返します。)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.