2017-05-19 9 views
0

私は、クライアントIP:ポート、サーバーIP:ポートとキーワードが行内に存在するかどうかを確認するために、ループしている各行に対してかなり大きなテキストファイル(〜16k行) 2つのforループを使用して、if x in lineステートメントをネストして、私が探している情報がその行に含まれているかどうかを確認します。ネストされたループのパフォーマンスが遅い

私が探している値を含む行を特定したら、sqlite DBを更新します。最初は、SQL UPDATE文が手動トランザクションでラップされていないため、実行にかなりの時間がかかりました。この変更を行った後、実行時間が大幅に改善されましたが、私はまだ以下のコードを完了するまでに数分かかりますが、私の恐ろしいループ構造が原因だと感じています。

誰でも以下のコードのスピードアップを支援するために、任意のパフォーマンスのヒントを持っていた場合、私は非常に感謝される:あなたのforループの場合

c.execute("SELECT client_tuple, origin_tuple FROM connections") 
# returns ~ 8k rows each with two items, clientIP:port and serverIP:port 
tuples = c.fetchall() 

with open('connection_details.txt', 'r') as f: 
    c.execute('BEGIN TRANSACTION') 
    # for each line in ~16k lines 
    for line in f: 
     # for each row returned from sql query 
     for tuple in tuples: 
      # if the client tuple (IP:Port) is in the line 
      if tuple[0] in line: 
       # if the origin tuple (IP:Port) is in the line 
       if tuple[1] in line: 
        # if 'foo' is in the line 
        if 'foo' in line: 
         # lookup some value and update SQL with the value found 
         bar_value = re.findall(r'(?<=bar\s).+?(?=\,)', line) 
         c.execute("UPDATE connections " 
            " SET bar = ? " 
            "WHERE client_tuple = ? AND origin_tuple = ?", 
            (bar_value[0], tuple[0], tuple[1])) 

    conn.commit() 
+0

変数名に 'tuple'を使うのは、組み込み関数なので避けてください。 – James

+0

'fetchall()'のような行の例とタプルの例を投稿すると、私たちがあなたを助けてくれるでしょう。 +あなたが非常に高速なメンバシップテストを持っているので 'any()'、 'all()'、* sets *を調べたいかもしれません。 –

+0

defitionによるネストループは遅いです。コードを微調整してもそれほど遠くには届きません。アルゴリズムを修正する必要があります。 – e4c5

答えて

6

if 'foo' in line:チェックは、for tuple in tuples:イテレータの前にする必要があります。

+0

ありがとう!私は 'if'ステートメントを再注文し、' tuple in tuples'ループに入る行数が減ったためにコード実行時間が半減しました。私はまた、2行の 'if tup [x] in line'行を@Jamesの提案に従って1つのステートメントに結合しました。私はもう少しパフォーマンスを絞り出すために、次に正規表現をコンパイルすることを検討します。それは大いに役立ちます。 – MarkoPolo

0

を、あなたはitertoolsを使用することができ、あなたが単一のものにあなたのif文を回すことができますそのように:あなたは、ファイル内の各行のタプルのすべてを反復処理する必要があるため

import itertools 

for line, tuple in itertools.product(f, tuples): 
    if tuple[0] in line and tuple[1] in line and 'foo' in line: 
5

残念ながら、あなたのforループを引き締めることができません。しかし、あなたはifステートメントを統合することでコードを若干強化することができます。おそらく、すべてのタプルを反復処理する前に、'foo'の存在を確認する必要があります。ループのcompile regexp外とコンパイルマッチャーを使用する - あなたは自動的に処理が

第2小改良必要はされていない行をスキップしまうので

with open('connection_details.txt', 'r') as f: 
    c.execute('BEGIN TRANSACTION') 
    # for each line in ~16k lines 
    for line in f: 
     # for each row returned from sql query 
     if 'foo' in line: 
      for tup in tuples: 
       if tup[0] in line and tup[1] in line: 
関連する問題