2009-04-13 18 views
4

私が知っていたときに書いたPythonコードの一部を掃除しています。主に私は、Pythonでのスレッド化の不完全な理解から生まれた複雑さの一部を取り除いています。スレッドセーフなアイテムのリストを作成する必要があります。通常のロック方法ではなく、不変なリストを使って行いたいと思います。私は、不完全な状態変化を取り巻くスレッド安全性の問題がすべて消えてしまうので、不変のオブジェクトはスレッディングに関して非常に特別であることを知っています。Pythonでの不変性とスレッドの安全性

私は次のコードがスレッドセーフであることを尋ねます:

class ImmutableList(object): 
    def __init__(self): 
     self._list =() 

    def __iter__(self): 
     return self._list.__iter__() 

    def append(self, x): 
     self._list = self._list + tuple([x]) 

毎回新しいリストが作成されると思います。他のスレッドが反復している間にリストが更新された場合、残りの反復で古いリストが引き続き使用されます。これは私にとっては大丈夫ですが、誰にとってもそうでないかもしれません。

また、これは良い考えですか?リストのサイズが小さく、リストがあまり変更されない(イベントリスナーが気になる)いくつかの状況にのみ適用したいと思います。

+4

をところで、あなたに「(X、)」「([X])タプル」を書くことができます。 –

答えて

15

まず、リストへの追加は、すでにPythonプログラミング言語のCPythonリファレンス実装ではスレッドセーフです。言い換えれば、言語仕様では、リストクラスがスレッドセーフである必要はありませんが、それはとにかくです。したがって、JythonやIronPythonなどのPython実装を使用している場合を除き、あなたはうまくいきます。

第2に、__setitem____setslice__などの他のリスト操作をオーバーロードする必要があります。私はあなたの実装がこれを処理していると仮定しています。

最後に、あなたの質問に対する答えは「いいえ」です。あなたのコードはスレッドセーフではありません。次のような状況を考えてみます。

  • あなたのリストが(5、6)
  • スレッド7を追加する1回の試行を、とスレッド8つの
  • スレッド1つの構造別のタプル(5、6、7を追加する2回の試行が含まれています)、それが_listに割り当てられる前に、コンテキストスイッチがあります
  • スレッド2が割り当てを実行するので、リストは今度は(5,6,8)
  • スレッド1はCPUバックの制御を取得し、_listに割り当てます前の追加を上書きします。リストは(5,6,7)になり、8は失われました。

このストーリーのモラルは、ロックを使用して賢明を避けることです。

+0

このケースは決して考えなかった...ありがとう! –

+1

+1:ロックを使用するだけです。 –

+2

コンクリートの場合は+1例 – wkschwartz

4

真の不変リストの実装では、あなたがここにいるように、元のリスト構造を変更することはできません。 @ [Eli Courtwright]が指摘するように、あなたの実装はスレッドセーフではありません。それは本当に不変ではないからです。不変実装を作るために、リストを変更したメソッドは、代わりに、望ましい変更を反映した新しいリストを返します。

あなたのコードの例に関しては

、これはこのような何かをするためにあなたを必要とする:

class ImmutableList(object): 
    def __init__(self): 
    self._list =() 

    def __iter__(self): 
    return self._list.__iter__() 

    def append(self, x): 
    return self._list + tuple([x]) 
+1

+1不変のデータ構造が実際にどのように機能するかの例です。ただし、複数のスレッドで同時に変更できるデータ構造を必要とするMatt Greenには、あなたの例は役に立たないと指摘しておきます。 –

+0

私は彼が本当に必要としているとは思っていませんが、実際には説明から必要なものを教えるのは難しいですが、彼は不変構造について話しているので、または彼は本当に不変の正しい使い方を理解していない –

関連する問題