2016-10-31 4 views
1

できるだけ早く、Pythonでオブジェクトのリストを更新したいと思います。私が今やっているが、次のコードで実証される:私の更新()関数のforループオブジェクトのリストを更新するループを高速化

from bokeh.models.sources import ColumnDataSource 
from random import randint 

n = 10 
m = 50 
sources = [] 
for i in range(n): 
    # all list elements have similar structure 
    sources.append(ColumnDataSource(data=dict(x=range(m), y=range(m), count=[0]))) 

def some_function(): 
    # do some computation 
    return [randint(0, m) for i in xrange(n)] 

def update(): 
    # this function is called every 20ms 
    for s in sources: 
     s.data = dict(x=some_function(), y=s.data['y'], count=[s.data['count'][0]+1]) 

ザ・は時間がかかりすぎます。私は更新するリストがたくさんあり、関数は20ミリ秒ごとに呼び出されます。場合によってはupdate()関数の実行に20ms以上かかることがあります。

私の現在の研究では、リストの補完はforループよりもはるかに高速ですが、私の場合は使用できません。のような:

#not working code 
sources = [dict(x=.., y=.., count=..) for s.data in sources] 
+1

リストの補完は高速ですが、たいていの場合、ほとんどの場合はμsecです。彼らは20ミリ秒の遅延を修正することはありません(そして、 'update 'の速度にはまったく影響がないでしょう、'ソースの初期構造のみ)。あなたは 'some_function'で何をしていますか?これは合理的に20ミリ秒以上かかる可能性のある唯一のものです。 – ShadowRanger

+2

私はこれを答えとして書いていますが、私はそれが完全であるとは思えません。プロフィール。はい、ループは遅いですが、それはほとんどの場合、あなたを減速させるものではありません。プロファイルの例については、http://stackoverflow.com/questions/582336/how-can-you-profile-a-python-scriptを参照してください。 – user2699

+0

それはまた言及する価値がある。 Bokehサーバーの目的は、Pythonプロセスを、ネットワーク上のアプリケーションのブラウザビューと自動的に同期させることです。 's.data = ... 'を設定すると、ブラウザのデータソースビューを更新するために* network communication *がトリガされます。あなたの質問から、20msの見積もりでネットワークアップデートの時間を含めるか除外したかは明らかではありません。 – bigreddot

答えて

0

確かにそれは速くなることは確かです。

sources = [ColumnDataSource(data=dict(x=some_function(), y=s.data['y'], count=[s.data['count'][0] + 1]) for s in sources] 

同じオブジェクトを使用する必要がある場合は、機能しません。

+0

@Guillaume:いいえ、更新機能用です。コメントを投稿する前にお読みください。 –

+0

@Guillaume:問題ありません。 –

0

initial forループと更新関数の両方にリストの理解を使用できます。

sources = [ColumnDataSource(data=dict(x=range(m), y=range(m), count=[0]) for i in range(n)] 

更新ループ:forループ

初期{'key': 'value, ...}表記と辞書を初期化

s_updated = [ColumnDataSource(data=dict(x=some_function(), y=s.data['y'], count=[s.data['count'][0]+1])) for s in sources] 
+0

「timeit」してください。新しい「ColumnDataSource」を作成するオーバーヘッドは、ポスターの現在のforループよりも遅くなる可能性があります。 – Guillaume

+0

いいえ、残念ながら、私の場合は動作しません。既存のオブジェクトを更新する必要があります。そうしないと、(ColumnDataSourceを使用する)javascriptの部分が変更を取得しません。 – jofroe

0

dict()を使用するよりも高速ですので、私はそれを使用したい:

timeit.timeit('{"a": 1, "b": 2}', number=1000000) 
0.1645284985700215 

timeit.timeit('dict(a=1, b=2)', number=1000000) 
0.4730025877568096 

結果:

def update(): 
    # this function is called every 20ms 
    for s in sources: 
     s.data = {'x': some_function(), 'y': s.data['y'], 'count': [s.data['count'][0]+1]} 

そして、この「カウント」はなぜリストですか?整数で十分です。

+0

'dict'コンストラクタを呼び出すのが遅くなります(一般的な' LOAD_GLOBAL' + 'CALL_FUNCTION'は最適化された' BUILD_MAP'よりもはるかに遅いです)。 'sources'が巨大でなければ意味がありません。あなたのマイクロベンチマークで 'dict'を使うのにかかる総コストは、構文ごとに1マイクロ秒の1/6であるのに対し、1回の使用では半分以下です。確かに、それはdictリテラルを使用するコストのおよそ3倍ですが、それはまだまだです。 'ソース 'の50個の値の場合、' dict'コンストラクタのオーバヘッドは約16マイクロ秒であり、20ミリ秒間隔の0.1%未満です。 – ShadowRanger

+0

dictコンストラクタを避けることは、コンストラクタ呼び出しを持つコードよりも少し遅くなることが分かります。 bokehのColumDataSourceはdictの各エントリが同じ長さであると仮定しているため、リストを使用していないとクラッシュするので、 'count'はリストです。 – jofroe

関連する問題