1

複数のスレッドを使用する場合は Lock オブジェクトを使用してカスタム クラスを保護する必要があると思いますが、Python は GIL を使用して常に 1 つのスレッドのみが実行されるようにするため、ビルトインを保護するために Lock を使用する必要がないということですか?リストのようなタイプ?例、

num_list = []
def consumer():
    while True:
        if len(num_list) > 0: 
            num = num_list.pop()
            print num
            return

def producer():
    num_list.append(1)

consumer_thread = threading.Thread(target = consumer)
producer_thread = threading.Thread(target = producer)
consumer_thread.start()
producer_thread.start()
4

2 に答える 2

1

GIL は、あなたの状態ではなく、インタープリターの状態を保護します。事実上アトミックな操作がいくつかあります。それらは単一のバイトコードを必要とするため、事実上ロックを必要としません。(非常に評判の良い Python 貢献者からの回答 については、 is python variable assignment atomic?を参照してください)。

ただし、これに関する適切なドキュメントは実際にはありません。したがって、仮定をテストするためにバイトコードを逆アセンブルする予定がない限り、一般的にはそれに依存しません。複数のコンテキストから状態を変更する (または複雑な状態を変更してアクセスする) ことを計画している場合は、ある種のロック/同期メカニズムの使用を計画する必要があります。

このクラスの問題に別の角度からアプローチすることに興味がある場合は、Queueモジュールを調べる必要があります。Python コードの一般的なパターンは、共有状態を操作するのではなく、同期キューを使用してスレッド コンテキスト間で通信することです。

于 2013-02-01T16:29:48.397 に答える
0

@jeremy-brown は言葉で説明しています (以下を参照)...しかし、反例が必要な場合:

ロックはあなたの状態を保護していません。次の例ではロックを使用していないため、xrange値が十分に大きい場合は失敗します。IndexError: pop from empty list.

import threading
import time
con1_list =[]
con2_list =[]
stop = 10000
total = 500000
num_list = []
def consumer(name, doneFlag):
    while True:
        if len(num_list) > 0: 
            if name == 'nix':
                con2_list.append(num_list.pop())
                if len(con2_list) == stop:
                    print 'done b'
                    return
            else:
                con1_list.append(num_list.pop())
                if len(con1_list) == stop:
                    print 'done a'
                    return
def producer():
    for x in xrange(total):
        num_list.append(x)

def test():
    while not (len(con2_list) >=stop and len(con1_list) >=stop):
        time.sleep(1)
    print set(con1_list).intersection( set(con2_list))

consumer_thread = threading.Thread(target = consumer, args=('nick',done1))
consumer_thread2 = threading.Thread(target = consumer, args=('nix',done2))
producer_thread = threading.Thread(target = producer)
watcher = threading.Thread(target = test)
consumer_thread.start();consumer_thread2.start();producer_thread.start();watcher.start()
于 2013-02-01T16:10:59.730 に答える