我应该在使用多个线程时保护内置数据结构(list,dict)吗?

时间:2013-02-01 15:59:32

标签: python

我认为在使用多个线程时我应该使用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()

2 个答案:

答案 0 :(得分:1)

GIL保护翻译状态,而不是你的状态。有些操作实际上是原子的 - 它们需要单个字节码,因此实际上不需要锁定。 (请参阅is python variable assignment atomic?以获得来自声誉卓着的Python撰稿人的答案)。

关于这一点并没有任何好的文档,所以我不会依赖它,除非你打算反汇编字节码来测试你的假设。如果您计划从多个上下文修改状态(或修改和访问复杂状态),那么您应该计划使用某种锁定/同步机制。

如果您对从不同角度处理此类问题感兴趣,请查看Queue模块。 Python代码中的一个常见模式是使用同步队列在线程上下文之间进行通信,而不是使用共享状态。

答案 1 :(得分: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()