1

我认为在使用多个线程时我应该使用 Lock 对象来保护自定义类,但是,因为 Python 使用 GIL 来确保在任何给定时间只有一个线程在运行,这是否意味着不需要使用 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

The GIL protects the interpreter state, not yours. There are some operations that are effectively atomic - they require a single bytecode and thus effectively do not require locking. (see is python variable assignment atomic? for an answer from a very reputable Python contributor).

There isn't really any good documentation on this though so I wouldn't rely on that in general unless if you plan on disassembling bytecode to test your assumptions. If you plan on modifying state from multiple contexts (or modifying and accessing complex state) then you should plan on using some sort of locking/synchronization mechanism.

If you're interested in approaching this class of problem from a different angle you should look into the Queue module. A common pattern in Python code is to use a synchronized queue to communicate among thread contexts rather than working with shared state.

于 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 回答