2016-12-19 12 views
3

1つのスレッドでネストされたリストに値を追加し、ネストしたリストをメインスレッドのリスト内包にコピーします。私の例ではスレッドロックを使用する必要がありますか?私はlist.append()メソッドis thread-safeを知っていますが、リスト内包でデータをコピーするときにロックを使用する必要がありますか?この例ではスレッドロックを使用する必要がありますか?

ロックを使用する必要がある場合、copy_data()でロックを使用するのは意味がありますが、GrowList._add_to_list()ではロックされていませんか?

import threading 
import time 

class GrowList(object): 
    def __init__(self): 
     self.data = [] 
     self.stop_event = threading.Event() 
     self.add_to_list() 

    def _add_to_list(self): 
     sample = [1, 2, 3, 4] 
     while not self.stop_event.is_set(): 
      self.data.append(sample) 
      time.sleep(1.0) 

    def add_to_list(self): 
     self.t = threading.Thread(target=self._add_to_list) 
     self.t.start() 

    def stop(self): 
     self.stop_event.set() 
     self.t.join() 


def copy_data(nested_list): 
    return [row[:] for row in nested_list] 
+0

のように書くことができ、リストの内包表記を可能__iter__方法を 。リストの理解の実行が評価されている間に追加の要素が追加される可能性があるので、リストのすべての要素をコピーしないことになります。 CPythonの現在の実装では、リストの末尾に順方向に反復しながら追加すると、通常は期待どおりに動作します。最悪の場合は、予期しないコピー結果(スキップされた要素など)が発生します。 – dhke

+0

私の 'copy_data'の必要条件は、関数が呼び出された時点でネストされたリスト内のすべての要素を取り出すことです。コピー中に追加されたアイテムがコピーされなかった場合は問題ありません。この要件を念頭に置いて、ロックを使用しないことは容認できますか? – Jakub

+0

それには保証はありません。 Pythonの保証は、マルチスレッドアクセス中にリストに「ダメージを与える」ことができないことです。つまり、リストの理解中にアイテムが追加されると、リストの内容の一部が取得されます。それが大丈夫なら、GILだけが必要です。それ以外の場合は、ロックを使用します。とにかくGILはそこにあることに注意してください。 – dhke

答えて

1

私は他に追加しながら、あなたは一つのスレッド に反復するために、少なくともロックを必要とするだと思う、と私はときにデータをコピーするとき、それはロックを使用する 意味がありませんと思うリストに追加するときには、 ロックを使用しないでください。ロックを使用するポイント は、リストの所有権を主張することです。

あなたが聞くかもしれないもう1つの質問は、ロックを使用して ではないことです。self.data = []で置き換えてself.data = MySafeList()と に置き換えるだけで、小さなスレッドセーフリストクラスをロックで個別に作成することで、コードをきれいに保つことができます。 数多くの @synchronizedデコレータの1つを使用して簡単に作成できます。たとえば、あなたの要件が何であるかに依存 が

@synchronized 
def __iter__(self): 
    return iter(list(list.__iter__(self))) 
関連する問題