python 中的with lock 的含义

global total

    try:
        html = etree.HTML(item)
        result = html.xpath('//div[contains(@id,"qiushi_tag")]')
        for site in result:
            try:
                imgUrl = site.xpath('.//img/@src')[0]
                title = site.xpath('.//h2')[0].text
                content = site.xpath('.//div[@class="content"]/span')[0].text.strip()
                vote = None
                comments = None
                try:
                    vote = site.xpath('.//i')[0].text
                    comments = site.xpath('.//i')[1].text
                except:
                    pass
                result = {
                    'imgUrl': imgUrl,
                    'title': title,
                    'content': content,
                    'vote': vote,
                    'comments': comments,
                }

                with self.lock:
                    # print 'write %s' % json.dumps(result)
                    self.f.write(json.dumps(result, ensure_ascii=False).encode('utf-8') + "\n")

            except Exception, e:
                print 'site in result', e
    except Exception, e:
        print 'parse_data', e
    with self.lock:
        total += 1
        
        

这里用了两次的with lock 第一个是加锁,防止竞争写资源,但是第二个为啥又是with lock 这两个啥关系?

阅读 14.1k
4 个回答

如果是多线程,total是class变量,如果没有加锁,多个线程同时对total操作,因为total += 1不是原子性操作,最后的结果就错了,所以要加个锁。

应该没啥关系,就是复用一个lock而已。

为了防止多线程同时修改total,如果不加锁,且不巧在处理过程中GIL做了切换,最后的数值就错了。

import dis
total = 0

def foo():
    global total
    total += 1

dis.dis(foo)

实际处理过程:

6             0 LOAD_GLOBAL              0 (total)
              2 LOAD_CONST               1 (1)
              4 INPLACE_ADD
              6 STORE_GLOBAL             0 (total)
              8 LOAD_CONST               0 (None)
             10 RETURN_VALUE

可见需要多个字节码的处理,再次过程中线程是可能切换的

两次是相同的,例如两个线程同时给total+1,如果不加锁,就会两个同时操作,导致total最终只+1,实际上是+2的

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题