Python学习日记-第三十三天-多线程共享全局变量

多个线程之间,是共享全局变量的

验证:

代码:

import threading
import time


# 定义一个全局变量
g_num = 100


def test1():
    global g_num
    g_num += 1
    print("----in test1 g_num=%d----" % g_num)


def test2():
    print("----in test2 g_num=%d----" % g_num)


def main():
    t1 = threading.Thread(target=test1)
    t2 = threading.Thread(target=test2)
    t1.start()
    time.sleep(1)

    t2.start()
    time.sleep(1)
    print("----in main Thread g_num = %d" % g_num)


if __name__ == "__main__":
    main()

输出结果:

 输出的值都是一样的

全局变量之所以能共享,是因为开发者在开发Python时考虑到,执行多任务时,往往是需要相互之间配合使用的。

多线程开发可能遇到的问题

假设两个线程test1和test2都要对全局变量g_num(默认=0)进项加1运算,两个线程都对g_num加10次,g_num最终结果应该为20

但由于是多线程同时操作,有可能出现下面情况:

  1. 在g_num=0时,t1取得的值是0,此时系统把t1调度为sleeping状态,把t2转化个为running状态,则t2取得值也是0
  2. 然后t2对得到的值进行加1并赋给t1,使得g_num= 1
  3. 然后系统又把t2调度为sleeping状态,t1转换为running状态,线程t1又把它之前得到的0加1后赋值给g_num
  4. 这样导致虽然t1和t2都对g_num加1,明明执行了两次加1,但是最后结果任然是g_num=1

验证:

 代码:

import threading
import time


# 定义一个全局变量
g_num = 0


def test1(num):
    global g_num
    for i in range(num):
        g_num += 1
    print("----in test1 g_num=%d----" % g_num)


def test2(num):
    global g_num
    for i in range(num):
        g_num += 1
    print("----in test2 g_num=%d----" % g_num)


def main():
    t1 = threading.Thread(target=test1, args=(1000000,))
    t2 = threading.Thread(target=test2, args=(1000000,))
    t1.start()
    t2.start()

    # 等待上面的两个线程执行完毕
    time.sleep(5)
    print("----in main Thread g_num = %d" % g_num)


if __name__ == "__main__":
    main()

输出结果:

 

相加的次数越多,后面的差值就越大 

这个问题是可以解决的:

可以通过线程同步来进行解决:

  1. 系统调用t1,然后获取到g_num的值为0,此时上一把锁,既不允许其他的线程操作g_num
  2. t1对g_num的值进行加1
  3. t1解锁,此时g_num的值为1,其他的线程就可以使用g_num了,而且是g_num的值不是0而是1
  4. 同理其他线程在对g_num进行修改是,都要先上锁,处理完成后再解锁

同步的概念:

同步就是协同步调,按预定的先后次序进行运行

互斥锁:

当多个线程几乎同时修改某一个共享数据时,需要进行同步控制

某个线程要更改共享数据时,现将其锁定,此时资源的状态为锁定,其他的线程不能操作更改,直到该线程释放资源,将资源的状态变成非锁定,其他的线程才能再次锁定该资源,互斥锁保证了每次只有一个线程进行操作,从而保证了多线程情况下数据的正确性

创建锁

mutex = threading.Lock()

锁定

mutex.acquire()

释放

murex.release()

·如果这个锁之前是没有上锁的,那么acquire不会堵塞

·如果在调用acquire对这个锁上锁之前,它已经被其他线程上锁,那么此时acquire会堵塞,直到这个锁被解锁为止

操作:

 代码:

import threading
import time


# 定义一个全局变量
g_num = 0


def test1(num):
    global g_num
    # 上锁,如果之前没有被上锁,此时上锁成功
    # 如果上锁之前,已经被上锁,会堵塞,直到被解锁
    mutex.acquire()
    for i in range(num):
        g_num += 1
    # 解锁
    mutex.release()
    print("----in test1 g_num=%d----" % g_num)


def test2(num):
    global g_num
    mutex.acquire()
    for i in range(num):
        g_num += 1
    mutex.release()
    print("----in test2 g_num=%d----" % g_num)


# 创建一个互斥锁,默认没有上锁的
mutex = threading.Lock()


def main():
    t1 = threading.Thread(target=test1, args=(10000000,))
    t2 = threading.Thread(target=test2, args=(10000000,))
    t1.start()
    t2.start()

    # 等待上面的两个线程执行完毕
    time.sleep(5)
    print("----in main Thread g_num = %d" % g_num)


if __name__ == "__main__":
    main()

输出结果:


版权声明:本文为arizia原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。