美文网首页
Threadlocal-线程隔离的全局变量

Threadlocal-线程隔离的全局变量

作者: 代码表演艺术家 | 来源:发表于2020-08-07 14:49 被阅读0次

多线程里,多个线程操作同一个全局对象会出现互相干扰的情况,为避免干扰,每个线程会使用局部变量,但是局部变量在单个线程的不同函数里使用需要不停的通过参数传递才能获得,这样很麻烦,python的多线程模块threading里提供了一个全局对象local, 每个线程可以使用这个对象来绑定属性值,且只能看到自己

下面通过三种情况来说明:

  • 普通全局变量的多线程干扰情况
  • 局部变量的冗余参数传递
  • threading.local 全局变量的线程隔离

1.普通全局变量的多线程干扰情况

import threading
import time
 
x = 0 #全局变量,所有子线程都可以修改
def worker():
    global x  # 指明是全局变量
    for i in range(100):
        time.sleep(0.01)
        x += 1
    print(threading.current_thread(),x)
 
for i in range(10):
    threading.Thread(target=worker).start()

输出:
 <Thread(Thread-1, started 11104)>
 <Thread(Thread-4, started 17116)>
 <Thread(Thread-3, started 15488)>
 <Thread(Thread-2, started 17128)>
 <Thread(Thread-5, started 16872)>
 <Thread(Thread-6, started 4600)>
 <Thread(Thread-9, started 13152)>
 <Thread(Thread-7, started 14368)>
 <Thread(Thread-10, started 16768)>
 <Thread(Thread-8, started 13592)>          
 991
 993
 994
 992
 995
 996
 998
 999
 1000
 997

分析输出:如果多线程之间不干扰应该都输出100的,但是因为每个线程都对全局变量x进行修改,造成x的值被10个线程累加,最早结束的线程都累加到了991,这就是普通全局变量在多线程操作里的干扰现象

2.局部变量的冗余参数传递

import threading
import time
 
def worker():
    x=0
    for i in range(100):
        time.sleep(0.01)
        x += 1
    print(threading.current_thread(), x)
 
for i in range(10):
    threading.Thread(target=worker).start()

输出:
Thread(Thread-1, started 596)>
<Thread(Thread-6, started 18256)>
<Thread(Thread-4, started 13020)>
<Thread(Thread-5, started 7836)>
<Thread(Thread-8, started 15452)>
<Thread(Thread-2, started 13852)>
<Thread(Thread-7, started 15708)>
<Thread(Thread-9, started 8248)>
<Thread(Thread-3, started 14560)>
<Thread(Thread-10, started 16908)>          
100
100
100
100
100
100
100
100
100
100

上面这种使用局部变量的方式可以确保每个子线程使用的都是单独的变量x,所以不会互相干扰,看上去很完美,但是如果单线程里有很多函数的话,每次调用都要显示传递x参数,例如:

import threading
import time
 
def worker():
    x=0
    for i in range(100):
        time.sleep(0.01)
        x += 1
    print1(x)
    print2(x)
    print(x)
 
def print1(x):
    print('aaaaaa',x)

def print2(x):
    print('bbbbbb',x)

for i in range(10):
    threading.Thread(target=worker).start()

上面这种要在单个线程里调用其它函数的时候,每次都要把局部变量x作为参数传递过去,这点类似django的视图函数,每个view函数的第一个参数都固定为request来接受请求的数据

3.threading.local 全局变量的线程隔离

import threading
import time
 
x = threading.local()#全局对象
 
def worker():
    x.num = 0
    for i in range(100):
        time.sleep(0.01)
        x.num += 1
    print1()
    print2()
    print(threading.current_thread(),x.num)
 
for i in range(10):
    threading.Thread(target=worker).start()


def print1():
    print('aaaaaa',x.num)

def print2():
    print('bbbbbb',x.num)

输出:(为了显示整洁,这里输出格式经过手动调整)
<Thread(Thread-3, started 14320)>
<Thread(Thread-1, started 16268)>
<Thread(Thread-2, started 16464)>
<Thread(Thread-9, started 16388)>
<Thread(Thread-6, started 15836)>
<Thread(Thread-8, started 12512)>
<Thread(Thread-5, started 15552)>
<Thread(Thread-10, started 1568)>
<Thread(Thread-4, started 9252)> 
<Thread(Thread-7, started 18128)> 
aaaaa 100
bbbbb 100
100
aaaaa 100
bbbbb 100
100
aaaaa 100
bbbbb 100
100
aaaaa 100
bbbbb 100
100
aaaaa 100
bbbbb 100
100
aaaaa 100
bbbbb 100
100
aaaaa 100
bbbbb 100
100
aaaaa 100
bbbbb 100
100
aaaaa 100
bbbbb 100
100
aaaaa 100
bbbbb 100
100

分析:
主线程里定义了threading.local全局对象x, 这个x有点类型字典,在每个子线程里都为这个x绑定了一个num属性,并且在循环里累加这个num属性,可以看到,这10个子线程对x的操作没有互相干扰,因为全局对象x为每个线程维护了独立字典,这里就相当于维护了10个独立字典,而这些字典都绑定了一个线程id, 所以每个线程来获取数据时,会通过线程的id来获取相应的字典,这就做到了每个线程只能获取到自己的数据。

同时,在调用print1(),print1()函数时,并没有像普通局部变量那样显示传递参数。
这其实就是flask里全局request对象的原理,flask的视图函数不需要像django那样需要request固定作为第一个参数,而是使用全局的request对象,import request 后就可以在任何视图函数里使用这个request对象了

相关文章

  • Threadlocal-线程隔离的全局变量

    多线程里,多个线程操作同一个全局对象会出现互相干扰的情况,为避免干扰,每个线程会使用局部变量,但是局部变量在单个线...

  • ThreadLocal

    线程间相互隔离的,线程内全局变量 并不是为了解决并发或者共享变量的问题 一般为static 的全局变量,方便整个线...

  • ThreadLocal

    线程变量,每一个线程中都维护了一个ThreadLocalMap对象,用于存放该线程中的ThreadLocal->O...

  • 多线程

    打印正在运行的多个线程 通过继承的方式实现线程 多线程共享全局变量 多线程共享全局变量 args参数 互斥锁 如果...

  • 线程间的通信、同步方式与进程间通信方式

    1、线程间的通信方式 使用全局变量主要由于多个线程可能更改全局变量,因此全局变量最好声明为volatile 使用消...

  • Hystrix

    容错方法 资源隔离 熔断 降级 资源隔离 资源隔离主要指对线程的隔离。Hystrix提供了两种线程隔离方式:线程池...

  • ThreadLocal-线程局部变量

    ThreadLocal不是一个线程,而是保存线程本地化对象的容器。多线程环境中,使用ThreadLocal维护变量...

  • Python学习7进程与线程3

    ThreadLocal 我们知道多线程环境下,每一个线程均可以使用所属进程的全局变量。如果一个线程对全局变量进行了...

  • 深入理解Python中的ThreadLocal变量(上)

    作者:selfboot 我们知道多线程环境下,每一个线程均可以使用所属进程的全局变量。如果一个线程对全局变量进行了...

  • 2018-08-26

    这周学习了多进程修改全局变量 多线程共享全局变量 UDP介绍

网友评论

      本文标题:Threadlocal-线程隔离的全局变量

      本文链接:https://www.haomeiwen.com/subject/mbefdktx.html