4

財務データ処理を扱う Djano アプリケーションを作成しています。次のように、MySQL テーブルから大きなデータ (1000000 レコード以上) をロードし、django ビューでレコードを JSON データに変換する必要があります。

trades = MtgoxTrade.objects.all()
data = []
for trade in trades:
            js = dict()
            js['time']= trade.time
            js['price']= trade.price
            js['amount']= trade.amount
            js['type']= trade.type
            data.append(js)
return data

問題は、FOR ループが非常に遅い (200000 レコードで 9 秒以上かかる) ことです。Python で DB レコードを JSON 形式のデータに変換する効果的な方法はありますか?

更新: ENV(ActivePython2.7,Win7) での Mike Housky の回答に従ってコードを実行しました。コードの変更と結果は次のとおりです。

def create_data(n):
    from api.models import MtgoxTrade
    result = MtgoxTrade.objects.all()

    return result


  Build ............ 0.330999851227
  For loop ......... 7.98400020599
  List Comp. ....... 0.457000017166
  Ratio ............ 0.0572394796312
  For loop 2 ....... 0.381999969482
  Ratio ............ 0.047845686326

for ループに約 8 秒かかることがわかります。Forループをコメントアウトすると、List Compにも次のような時間がかかります。

Times:
  Build ............ 0.343000173569
  List Comp. ....... 7.57099986076
  For loop 2 ....... 0.375999927521

私の新しい質問は、for ループがデータベースに触れるかどうかということです。しかし、DBアクセスログは見られませんでした。とても奇妙!

4

6 に答える 6

2

dict()多くのandappend()呼び出しを防ぐため、リスト内包表記を使用できます。

trades = MtgoxTrade.objects.all()
data = [{'time': trade.time, 'price': trade.price, 'amount': trade.amount, 'type': trade.type}
        for trade in trades]
return data

関数呼び出しは Python ではコストがかかるため、遅いループでは避けるようにしてください。

于 2013-09-20T11:32:54.090 に答える
1

この回答は、Simeon Visser の観察を支持するものです。次のコードを実行しました。

import gc, random, time
if "xrange" not in dir(__builtins__):
    xrange = range

class DataObject(object):
    def __init__(self, time, price, amount, type):
        self.time = time
        self.price = price
        self.amount = amount
        self.type = type

def create_data(n):
    result = []
    for index in xrange(n):
        s = str(index);
        result.append(DataObject("T"+s, "P"+s, "A"+s, "ty"+s))
    return result

def convert1(trades):
    data = []
    for trade in trades:
                js = dict()
                js['time']= trade.time
                js['price']= trade.price
                js['amount']= trade.amount
                js['type']= trade.type
                data.append(js)
    return data

def convert2(trades):
    data = [{'time': trade.time, 'price': trade.price, 'amount': trade.amount, 'type': trade.type}
        for trade in trades]
    return data

def convert3(trades):
    ndata = len(trades)
    data = ndata*[None]
    for index in xrange(ndata):
        t = trades[index]
        js = dict()
        js['time']= t.time
        js['price']= t.price
        js['amount']= t.amount
        js['type']= t.type
        #js = {"time" : t.time, "price" : t.price, "amount" : t.amount, "type" : t.type}
    return data

def main(n=1000000):

    t0s = time.time()
    trades = create_data(n);
    t0f = time.time()
    t0 = t0f - t0s

    gc.disable()

    t1s = time.time()
    jtrades1 = convert1(trades)
    t1f = time.time()
    t1 = t1f - t1s

    t2s = time.time()
    jtrades2 = convert2(trades)
    t2f = time.time()
    t2 = t2f - t2s

    t3s = time.time()
    jtrades3 = convert3(trades)
    t3f = time.time()
    t3 = t3f - t3s

    gc.enable()

    print ("Times:")
    print ("  Build ............ " + str(t0))
    print ("  For loop ......... " + str(t1))
    print ("  List Comp. ....... " + str(t2))
    print ("  Ratio ............ " + str(t2/t1))
    print ("  For loop 2 ....... " + str(t3))
    print ("  Ratio ............ " + str(t3/t1))

main()

Win7、Core 2 Duo 3.0GHz での結果: Python 2.7.3:

Times:
  Build ............ 2.95600008965
  For loop ......... 0.699999809265
  List Comp. ....... 0.512000083923
  Ratio ............ 0.731428890618
  For loop 2 ....... 0.609999895096
  Ratio ............ 0.871428659011

Python 3.3.0:

Times:
  Build ............ 3.4320058822631836
  For loop ......... 1.0200011730194092
  List Comp. ....... 0.7500009536743164
  Ratio ............ 0.7352942070195492
  For loop 2 ....... 0.9500019550323486
  Ratio ............ 0.9313733946208623

GC が無効になっている場合でも、これらは少し異なります (GC が有効になっている場合はより多くの差異がありますが、結果はほぼ同じです)。3 番目の変換タイミングは、節約された時間のかなりの部分が .append() を 100 万回呼び出さなかったことによるものであることを示しています。

「For loop 2」の時間は無視してください。このバージョンにはバグがあり、今のところ修正する時間がありません。

于 2013-09-20T14:46:11.120 に答える
0

モデルは多くの余分な定型コードをフィールドに配置し (フィールドはプロパティであると信じています)、前述のように関数呼び出しは高価であるため、データベースに対して生のクエリを実行する価値があると思います。ドキュメントを参照してください。ページの下部に、あなたが求めているもののように見える dictfetchall を使用する例があります。

于 2013-09-20T15:44:01.083 に答える
0

最初に、データベースからデータをフェッチしている間、またはループ内でパフォーマンスの低下が発生しているかどうかを確認する必要があります。

大幅なスピードアップを実現するための実際のオプションはありません-上記のようにリスト内包表記を使用しないこともできます。

ただし、Python 2 と 3 ではパフォーマンスに大きな違いがあります。

簡単なベンチマークでは、for ループが Python 3.3 で約 2.5 倍高速であることがわかりました (次のような簡単なベンチマークを使用)。

import time

ts = time.time()
data = list()
for i in range(1000000):
    d = {}
    d['a'] = 1
    d['b'] = 2
    d['c'] = 3
    d['d'] = 4
    d['a'] = 5
    data.append(d)

print(time.time() - ts)



/opt/python-3.3.0/bin/python3 foo2.py 
0.5906929969787598

python2.6 foo2.py 
1.74390792847

python2.7 foo2.py 
0.673550128937

また、Python 2.6 と 2.7 ではパフォーマンスに大きな違いがあることにも注意してください。

于 2013-09-20T11:42:43.027 に答える