今天看啥  ›  专栏  ›  DevOps海洋的渔夫

Python 多线程 - 共享变量

DevOps海洋的渔夫  · 简书  ·  · 2018-12-19 22:20

仅用学习参考

多线程-共享全局变量

#coding=utf-8
from threading import Thread
import time

g_num = 100

def work1():
    global g_num
    for i in range(3):
        g_num += 1

    print("----in work1, g_num is %d---"%g_num)


def work2():
    global g_num
    print("----in work2, g_num is %d---"%g_num)


print("---线程创建之前g_num is %d---"%g_num)

t1 = Thread(target=work1)
t1.start()

#延时一会,保证t1线程中的事情做完
time.sleep(1)

t2 = Thread(target=work2)
t2.start()

执行如下:

[root@server01 many_task]# python test5.py 
---线程创建之前g_num is 100---
----in work1, g_num is 103---
----in work2, g_num is 103---
[root@server01 many_task]# 

从上面两个线程执行的结果来看,线程t1g_num 加到 103,在线程t2也是打印g_num=103。所以对于两个线程,g_num这个全局变量是共享的。

列表当做实参传递到线程中

#coding=utf-8
from threading import Thread
import time

def work1(nums):
    nums.append(44)
    print("----in work1---",nums)


def work2(nums):
    #延时一会,保证t1线程中的事情做完
    time.sleep(1)
    print("----in work2---",nums)

g_nums = [11,22,33]

t1 = Thread(target=work1, args=(g_nums,))
t1.start()

t2 = Thread(target=work2, args=(g_nums,))
t2.start()

运行如下:

[root@server01 many_task]# python test6.py 
('----in work1---', [11, 22, 33, 44])
('----in work2---', [11, 22, 33, 44])

总结:
在一个进程内的所有线程共享全局变量,很方便在多个线程间共享数据
缺点就是,线程是对全局变量随意遂改可能造成多线程之间对全局变量的混乱(即线程非安全)

多线程-共享全局变量问题

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

  • 假设两个线程t1t2都要对全局变量g_num(默认是0)进行加1运算,t1t2都各对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
    这样导致虽然t1t2都对g_num1,但结果仍然是g_num=1

编写代码测试如下:

[root@server01 many_task]# vim test4.py 

#coding=utf-8
import threading
from time import sleep,ctime

# 初始化g_num
g_num = 0

def add_func1(num):
    global g_num
    for i in range(num):
        g_num += 1
        print("add_func1,第%d次,g_num等于%d" % (i,g_num))
        #sleep(0.5)

def add_func2(num):
    global g_num
    for i in range(num):
        g_num += 1
        print("add_func2,第%d次,g_num等于%d" % (i,g_num))
        #sleep(0.5)

def main():
    # 执行线程
    t1 = threading.Thread(target=add_func1,args=(100,))
    t2 = threading.Thread(target=add_func2,args=(100,))

    t1.start()
    t2.start()

    # 判断当线程存在,则等待1秒
    while len(threading.enumerate()) > 1:
        sleep(1)

    print("2个线程对同一个全局变量操作之后的最终结果是:%s" % g_num)

if __name__ == '__main__':
    main()

执行如下:

add_func2,第96次,g_num等于197
add_func2,第97次,g_num等于198
add_func2,第98次,g_num等于199
add_func2,第99次,g_num等于200
2个线程对同一个全局变量操作之后的最终结果是:200
[root@server01 many_task]# 

两个线程虽然执行很快,但是g_num恰好就是100+100=200的结果,是正确的。不过,这个数量少,可能看不出问题来。

测试示例2

[root@server01 many_task]# vim test7.py 


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


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


print("---线程创建之前g_num is %d---"%g_num)

t1 = threading.Thread(target=work1, args=(10000000,))
t1.start()

t2 = threading.Thread(target=work2, args=(10000000,))
t2.start()

while len(threading.enumerate()) != 1:
    time.sleep(1)

print("2个线程对同一个全局变量操作之后的最终结果是:%s" % g_num)

运行如下:

[root@server01 many_task]# python test7.py 
---线程创建之前g_num is 0---
----in work1, g_num is 11977799---
----in work2, g_num is 19108796---
2个线程对同一个全局变量操作之后的最终结果是:19108796
[root@server01 many_task]# 

正确的结果应该是:20000000

结论
如果多个线程同时对同一个全局变量操作,会出现资源竞争问题,从而数据结果会不正确


关注微信公众号,回复【资料】、Python、PHP、JAVA、web,则可获得Python、PHP、JAVA、前端等视频资料。




原文地址:访问原文地址
快照地址: 访问文章快照