2

マルチスレッドの Python プログラムを作成しています。このプログラムでは、ワーカー スレッドを起動して入力データのリストを処理しています。それらが処理するデータはネットワーク操作を必要とするため、実質的に I/O バウンドになります (したがって、GIL は私にとって問題ではありません)。

複数のワーカー スレッドが明らかに同じ入力を受信して​​いるという問題が発生していますが、その理由がわかりません。私が知る限り、スレッド間でスレッドセーフでないデータを共有していません。

私がやろうとしていることの最小化されたバージョンを作成しました。このプログラムは、I/O などを何も実行せずに問題を示します。

#!/usr/bin/env python

import threading
import logging
import time

logging.basicConfig(level=logging.DEBUG,
                    format="%(threadName)-10s %(levelname)-7s %(message)s")

sema = threading.Semaphore(10)

# keep track of already-visited data in worker threads
seen = []
seenlock = threading.Lock()

def see(num):
    try:
        logging.info("see: look at %d", num)

        with seenlock:
            if num in seen:
                # this should be unreachable if each thread processes a unique number
                logging.error("see: already saw %d", num)
            else:
                seen.append(num)

        time.sleep(0.3)

    finally:
        sema.release()


def main():
    # start at 1, so that the input number matches the log's "Thread-#"
    for i in xrange(1, 100):
        sema.acquire() # prevent more than 10 simultaneous threads
        logging.info("process %d", i)
        threading.Thread(target=lambda: see(i)).start()

if __name__ == '__main__': main()

出力の一部:

MainThread INFO    process 1
MainThread INFO    process 2
Thread-1   INFO    see: look at 2
Thread-2   INFO    see: look at 2
MainThread INFO    process 3
Thread-2   ERROR   see: already saw 2
MainThread INFO    process 4
Thread-3   INFO    see: look at 4
Thread-4   INFO    see: look at 4
MainThread INFO    process 5
Thread-4   ERROR   see: already saw 4
Thread-5   INFO    see: look at 5
MainThread INFO    process 6
Thread-6   INFO    see: look at 6
MainThread INFO    process 7
Thread-7   INFO    see: look at 7
MainThread INFO    process 8
Thread-8   INFO    see: look at 8
MainThread INFO    process 9
MainThread INFO    process 10

私がやっている唯一の奇妙なことは、セマフォが解放される場所以外のスレッドでセマフォ許可を取得することですが、セマフォはスレッドセーフであり、誰が許可を取得して解放するかについては気にしない必要があります。それぞれ同数。

確認日:

  • Python 2.7.3 (Windows; python.org からビルド)
  • Python 2.6.7 (Windows; cygwin dist)
  • Python 2.6.6 (Linux; Debian ディストリビューション)

スレッドでデータを共有するにはどうすればよいですか?

4

1 に答える 1

3

これはスレッド化とは関係ありません。これは、クロージャの動作に関係しています。

>>> funcs = []
>>> for x in range(10):
...     def foo():
...         return x
...     funcs.append(foo)
... 
>>> [f() for f in funcs]
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]

関数を定義し、外側のスコープで変数を参照すると、その変数の値は、関数の呼び出し時に常に外側のスコープ内のその変数の値になります。これらの関数はすべてループの終了後に呼び出されるため、10 回の呼び出しすべてについてです。forx == 9

この問題を解決する簡単な方法は、デフォルト値を使用することです。要するに、これを変更します。

    threading.Thread(target=lambda: see(i)).start()

これに:

    threading.Thread(target=lambda x=i: see(x)).start()

または、さらに良いのは、Threadコンストラクターの全機能を使用することです (思い出させてくれた Joel Cornett に感謝します)。

    threading.Thread(target=see, args=(i,)).start()
于 2012-07-14T19:36:45.167 に答える