【Python3 爬虫】U25_多线程爬虫之多线程共享全局变量及锁机制

1.共享全局变量

1.1 共享全局变量问题

在一个进程内的所有线程共享全局变量,很方便在多个线程之间共享数据,但是存在一个缺点,当线程无序执行的时候,会导致全局变量的混乱,导致数据错误。
例如:
假设两个线程t1和t2都要对全局变量g_num(默认是0)进行加1运算,t1和t2都各对g_num加10次,g_num的最终的结果应该为20。
但是由于是多线程同时操作,有可能出现下面情况:

  • 在g_num=0时,t1取得g_num=0。此时系统把t1调度为"sleeping"状态,把t2转换为"running"状态,t2也获得g_num=0
  • 然后t2对得到的值进行加1并赋给g_num,使得g_num=1
  • 然后系统又把t2调度为”sleeping”,把t1转为”running”。线程t1又把它之前得到的0加1后赋值给g_num。
  • 这样导致虽然t1和t2都对g_num加1,但结果仍然是g_num=1

1.2 示例

import threading
num = 0

def get_num():
    global num
    for i in range(1000000):
        num += 1
    print("num的值为:%d" %num)

def main():
    # 启动2个线程对执行函数get_num
    for x in range(2):
        t = threading.Thread(target=get_num)
        t.start()
   
if __name__ == '__main__':
    main()

本次执行结果:(每次执行结果都不一样)
num的值为:1104111
num的值为:1185898

从上述结果可以看到,两次的和按照常理来说应该是2000000,但实际却不是,说明出现了线程安全问题。

3.锁机制

对于上述问题,结论是:如果多个线程同时对同一个全局变量操作,会出现资源竞争问题,从而数据结果会不正确
那么如何来解决这个问题呢?
我们可以将上述函数的调用加上一把锁,比如线程1准备执行这个函数,那么先把这个函数锁起来,此时,就不允许其他线程来操作,如果要操作,不好意思,得等我执行完,不然,没门。这样就可以保证每次执行函数的时候,全局变量不会同时被2个线程拿到,就解决了资源争夺问题了。下面是具体的代码示例:

import threading
num = 0
g_lock = threading.Lock()
def get_num():
    global num
    g_lock.acquire()
    for i in range(1000000):
        num += 1
    g_lock.release()
    print("num的值为:%d" %num)

def main():
    # 启动2个线程对执行函数get_num
    for x in range(2):
        t = threading.Thread(target=get_num)
        t.start()

if __name__ == '__main__':
    main()

执行结果:

num的值为:1000000
num的值为:2000000

posted @ 2020-04-04 15:36  OLIVER_QIN  阅读(383)  评论(0编辑  收藏  举报