【问题标题】:should I protect built-in data structure( list, dict) when using multiple threads?使用多线程时我应该保护内置数据结构(列表、字典)吗?
【发布时间】:2013-02-01 15:59:32
【问题描述】:

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

【问题讨论】:

  • 你为什么不生成一个运行不止一次的工作示例.....

标签: python


【解决方案1】:

GIL 保护解释器状态,而不是你的。有些操作实际上是原子的——它们需要单个字节码,因此实际上不需要锁定。 (请参阅is python variable assignment atomic? 以获取一位非常有名的 Python 贡献者的回答)。

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

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

【讨论】:

    【解决方案2】:

    @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()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-02
      • 2016-03-06
      • 2010-12-22
      • 2012-05-18
      • 2013-04-15
      • 2017-11-29
      相关资源
      最近更新 更多