2017-05-14 7 views
1

python 2.7で、ディレクトリ内のすべてのファイルを読み込んで内容を集計する必要があるプログラムがあります。今、私はそうのようなシングルスレッド次々にこれをやっている:Pythonで複数のファイルを読み込む方法を最適化する方法

def read_file(path): 
with open(path, 'r') as f: 
    return f.read() 
files = map(read_file, paths) 

私は読書の前に読み込まれるファイルごとに待機する必要がないように、しかし私は、これを最適化したいと思います次の私は、並行してこれを行う方法で検索すると、マルチプロセッシング、スレッドとキューを使用したなど、いくつかの解決策を思い付いた、これらの最速は、次のされてきた:

from threading import Thread 
import Queue 

def add_to_queue(q, f): 
    q.put(read_file(f)) 
q = Queue.Queue() 
files = [] 
for f in paths: 
    t = Thread(target=add_to_queue, args = (q, f)) 
    t.daemon = True 
    t.start() 
for f in paths: 
    files.append(q.get()) 

しかし、多くのオプションを結ぶ後、読書します1つのスレッド上のファイルは、これを実行する最速の方法のように見えます。私はここに何かを逃していますかこれを行う最も効率的な方法は何ですか?

答えて

1

実際に1つのディスクから複数のファイルを読み取っていると仮定すると、操作はのCPUバインドではなく、I/Oバインドになります。

マルチプロセッシング、キューイング、マルチスレッド、曲げ、折り畳み、ねじれ、フープジャンプ、またはその他のジムクラッカーリは、ディスクスピンドルの回転を速くすることも、ヘッドをシリンダ全体でより速く動かすこともありません。

パフォーマンスを向上させるには、I/Oパフォーマンスを向上させるか、ソリューションに対する別のアプローチを検討してください。 (異なるサーバーが別々のサーバーを提供するようにアーキテクチャーを再設計できますか、または少数のサーバーがあるか... ...)

ファイルのサイズと数に応じて、 SSDドライブ、複数のドライブの使用、RAIDコントローラの使用、SANの使用、サーバークラスタの使用などがあります。

+0

おかげで、私は今、ソフトウェアソリューションとハードウェアの制限を解決しようとするために少し愚かな感じ!私は最善の解決策は、ソフトウェアを再設計して、各ファイルを読み込みながらストリームしてから、すべてを読み終えてから続けることだと思います。 –

0

ディスクからの読み取りは、連続した操作です。プロセスの数は関係ありませんが、基本的には一度に1つだけ読み取ります。並行処理は、すでに読み込まれたファイルの特定の文字列や正規表現ファイルの内容を検索するなど、ファイルの読み取り中に他の操作を実行する必要がある場合に便利です。

0

スレッドを使用して、DB内のデータレイクにデータを設定します。キーEDAを記録するブレークポイントを使用して更新し、照会します。処理を高速化し、ファイル全体を集約すると、より多くの時間を消費することになります。私はFP成長アルゴリズムを使ってBSONファイルを作成しました。

class FPTreeNode(): 
    def __init__(self, item=None, support=1): 
     # 'Value' of the item 
     self.item = item 
     # Number of times the item occurs in a 
     # transaction 
     self.support = support 
     # Child nodes in the FP Growth Tree 
     self.children = {} 


class FPGrowth(): 
    def __init__(self, min_sup=0.3): 
     self.min_sup = min_sup 
     # The root of the initial FP Growth Tree 
     self.tree_root = None 
     # Prefixes of itemsets in the FP Growth Tree 
     self.prefixes = {} 
     self.frequent_itemsets = [] 

    # Count the number of transactions that contains item. 
    def _calculate_support(self, item, transactions): 
     count = 0 
     for transaction in transactions: 
      if item in transaction: 
       count += 1 
     support = count 
     return support 

    # Returns a set of frequent items. An item is determined to 
    # be frequent if there are atleast min_sup transactions that 
    contains 
    # it. 
    def _get_frequent_items(self, transactions): 
     # Get all unique items in the transactions 
     unique_items = set(
     item for transaction in transactions for item in transaction) 
     items = [] 
     for item in unique_items: 
      sup = self._calculate_support(item, transactions) 
      if sup >= self.min_sup: 
       items.append([item, sup]) 
     # Sort by support - Highest to lowest 
     items.sort(key=lambda item: item[1], reverse=True) 
     frequent_items = [[el[0]] for el in items] 
     # Only return the items 
     return frequent_items 

    # Recursive method which adds nodes to the tree. 
    def _insert_tree(self, node, children): 
     if not children: 
      return 
     # Create new node as the first item in children list 
     child_item = children[0] 
     child = FPTreeNode(item=child_item) 
     # If parent already contains item => increase the support 
     if child_item in node.children: 
      node.children[child.item].support += 1 
     else: 
      node.children[child.item] = child 

     # Execute _insert_tree on the rest of the children list 
     # from the new node 
     self._insert_tree(node.children[child.item], children[1:]) 

    def _construct_tree(self, transactions, frequent_items=None): 
     if not frequent_items: 
      # Get frequent items sorted by support 
      frequent_items = self._get_frequent_items(transactions) 
     unique_frequent_items = list(
     set(item for itemset in frequent_items for item in itemset)) 
     # Construct the root of the FP Growth tree 
     root = FPTreeNode() 
     for transaction in transactions: 
      # Remove items that are not frequent according to 
      # unique_frequent_items 
      transaction = [item for item in transaction 
      if item in unique_frequent_items] 
      transaction.sort(key=lambda item:  
       frequent_items.index([item])) 
       self._insert_tree(root, transaction) 

     return root 

    # Recursive method which prints the FP Growth Tree 
    def print_tree(self, node=None, indent_times=0): 
     if not node: 
      node = self.tree_root 
     indent = " " * indent_times 
     print ("%s%s:%s" % (indent, node.item, node.support)) 
     for child_key in node.children: 
      child = node.children[child_key] 
      self.print_tree(child, indent_times + 1) 

    # Makes sure that the first item in itemset 
    # is a child of node and that every following item 
    # in itemset is reachable via that path 
    def _is_prefix(self, itemset, node): 
     for item in itemset: 
      if not item in node.children: 
       return False 
      node = node.children[item] 
     return True 

    # Recursive method that adds prefixes to the itemset by 
    # traversing the FP Growth Tree 
    def _determine_prefixes(self, itemset, node, prefixes=None): 
     if not prefixes: 
      prefixes = [] 

     # If the current node is a prefix to the itemset 
     # add the current prefixes value as prefix to the itemset 
     if self._is_prefix(itemset, node): 
      itemset_key = self._get_itemset_key(itemset) 
      if not itemset_key in self.prefixes: 
       self.prefixes[itemset_key] = [] 
      self.prefixes[itemset_key] += [{"prefix": prefixes,  
      "support": node.children[itemset[0]].support}] 

     for child_key in node.children: 
      child = node.children[child_key] 
      # Recursive call with child as new node. Add the child 
      #item as potential 
      # prefix. 
      self._determine_prefixes(itemset, child, prefixes + 
      [child.item]) 

    # Determines the look of the hashmap key for self.prefixes 
    # List of more strings than one gets joined by '-' 
    def _get_itemset_key(self, itemset): 
     if len(itemset) > 1: 
      itemset_key = "-".join(itemset) 
     else: 
      itemset_key = str(itemset[0]) 
     return itemset_key 

    def _determine_frequent_itemsets(self, conditional_database, 
    suffix): 
    # Calculate new frequent items from the conditional database 
    # of suffix 
     frequent_items = 
     self._get_frequent_items(conditional_database) 

     cond_tree = None 

     if suffix: 
      cond_tree = self._construct_tree(conditional_database, 
      frequent_items) 
      # Output new frequent itemset as the suffix added to the 
      # frequent 
      # items 
      self.frequent_itemsets += [el + suffix for el in 
      frequent_items] 

     # Find larger frequent itemset by finding prefixes 
     # of the frequent items in the FP Growth Tree for the # 
     # conditional 
     # database. 
     self.prefixes = {} 
     for itemset in frequent_items: 
      # If no suffix (first run) 
      if not cond_tree: 
       cond_tree = self.tree_root 
      # Determine prefixes to itemset 
      self._determine_prefixes(itemset, cond_tree) 
      conditional_database = [] 
      itemset_key = self._get_itemset_key(itemset) 
      # Build new conditional database 
      if itemset_key in self.prefixes: 
       for el in self.prefixes[itemset_key]: 
        # If support = 4 => add 4 of the corresponding 
        # prefix set 
        for _ in range(el["support"]): 
         conditional_database.append(el["prefix"]) 
       # Create new suffix 
       new_suffix = itemset + suffix if suffix else itemset 
       self._determine_frequent_itemsets(conditional_database, suffix=new_suffix) 

    def find_frequent_itemsets(self, transactions, suffix=None,  
    show_tree=False): 
     self.transactions = transactions 

     # Build the FP Growth Tree 
     self.tree_root = self._construct_tree(transactions) 
     if show_tree: 
      print ("FP-Growth Tree:") 
      self.print_tree(self.tree_root) 

     self._determine_frequent_itemsets(transactions, suffix=None) 

     return self.frequent_itemsets 

デフメイン():

関連する問題