2011-10-25 9 views
4

Pythonでスレッドセーフソートコレクションの実装がありますか?
Python's docs参照SortedCollectionしかし、スレッドセーフであればわかりません(それは?)
このような実装がない場合、どのように実装しますか?スレッドセーフなソートコレクション

+0

実際に私は、Pythonにそのようなクラスが組み込まれていない理由は実際にはわかりません。 – Jonathan

答えて

1

PythonはJavaとは異なります。クラスがドキュメント内でスレッド動作を指定していない場合は、スレッドセーフではないと見なすのが安全です。

Pythonはスレッディングを念頭に置いて書かれていません。今日でも、マルチスレッドは実際には2つのクラスの市民であり、常に1つのスレッドしかアクティブではありません(ほとんどのデータ競合の問題を防ぎません)。これは、グローバルインタープリターロック(GIL)と呼ばれます。

クラスまたはデータ構造は、同時実行のために構築されていない場合は、コードを見ると、スレッドセーフであるとは思われないexternal lock

+0

これは実際にJavaと全く違うものではありません。 Javaでは、スレッディングに関して何も言及されていない場合、スレッドセーフではないと想定するのは安全です。 Pythonとは逆に、スレッドセーフなコレクションを手に入れますが、悲しいことに、Pythonの点では/ – Voo

3

によって、それへのアクセスを保護する必要があります。それを複数のスレッドから使​​用するには、それにアクセスするアプリケーションコードをセマフォーロックで保護する必要があります。

SortedCollectionクラスをスレッドセーフにしたい場合は、デコレータ関数を記述することができます。

それは次のようになります。

のSortedCollection:スレッドセーフデータ構造は、アプリケーションコードのスレッドを作ることを考えてのミスをしないでください

def __init__(self): 
    self.mysemaphore = threading.Semaphore() 

def guard(func): 
    def guarded(*args, **kwds): 
     self.mysemaphore.acquire() 
     try: 
      return func(*args, **kwds) 
     finally: 
      self.mysemaphore.release() 

return guarded 

# edit the class, applying the decorator to its methods. 
@guard 
def unsafeFunc(self, a, b, c): 
    ''' do work here''' 

EDIT

安全。 SortedCollectionで複数の操作を実行する場合、それらの操作はすべてロックによって保護される必要があります。 SortedCollectionは、スレッドセーフであっても

は、次のコードはないであろう。

slist.insert(1) 
slist.insert(2) 

別のスレッドがそれらの2文の間にアイテムを挿入することが可能です。アプリケーションコード内でガードする必要があります。これをアプリケーションコードに追加すると、SortedCollectionをスレッドセーフに変更する必要はありません。

semaphore2.acquire() 

try: 
    slist.insert(1) 
    slist.insert(2) 
finally: 
    semaphore2.release() 
+0

がありません.funcがセマフォのリリースをブロックしませんか? – Eduardo

+1

@eduardocereto docs: 'try節の他の句がブレーク、continue、return文を介して残っているときにfinally節も「途中で」実行されます。 ' – rplnt

+0

デコレータの素晴らしい使い方! –

1

collections.OrderedDictクラスは、更新のためにスレッドセーフではありません。並行読み取りは可能ですが、書き込みにはロックが必要です。 のOrderedDictでロックを使用する方法の例については、functools.lru_cache()のソースを参照してください。

0

heapqモジュールを使用すると、並べ替えられたリストを維持できます。 GILの力により、Cエクステンションへのすべての呼び出しはアトミック(拡張が明示的にロックを解除しない限り、CPythonで)であるため、heappushとフレンドはスレッドセーフです。

from heapq import heappush, heappop 

class Heap: 

    def __init__(self): 
     self._heap = [] 

    def push(self, x): 
     heappush(self._heap, x) 

    def pop(self): 
     return heappop(self.heap) 
+0

... 'heapq'はCの拡張子ではありません! 'heapq'は純粋なpythonで実装されています。 [コード](http://hg.python.org/cpython/file/2.7/Lib/heapq.py)を参照してください。クイックルックから、 'heapq'はスレッドセーフではありません。 – Russ

+4

また、 'heapq'関数自体はスレッドセーフではありませんが、[Queue](http://docs.python.org/library/queue.html)モジュールの[PriorityQueue](http ://docs.python.org/library/queue.html#Queue.PriorityQueue)はスレッドセーフであり、 'heapq'を内部的に使用します。 – Russ

0

アトミック操作は、常にPythonではスレッドセーフです。操作がアトミックでない場合は、同期する必要があります。 GILは、スレッドの数に関係なく、一度に1つのアトミック操作しか実行できません。 Pythonでのマルチプロセッシングは別の問題です。

関連する問題