python threading.loca讲解

1.全局变量

多个线程同时对一个全局变量操作,可能会产生脏数据

import threading
global_num = 0

def thread_cal():
    global global_num
    for i in range(100000):
        global_num += 1

threads = []
for i in range(10):
    threads.append(threading.Thread(target=thread_cal))
    threads[i].start()
for i in range(10): # 必须在全部start之后再join,不然每启动一个线程,主线程都会被阻塞,既10个线程依次进行
    threads[i].join()
print(global_num) # 值不确定

2.局部变量

每个线程的局部变量是互相受影响的

import threading

def thread_cal():
    local_num = 0
    for _ in range(1000):
        local_num += 1
    print(threading.current_thread().getName(), num)

threads = []
for i in range(10):
    threads.append(threading.Thread(target=thread_cal))
    threads[i].start()

3.使用字典实现全局变量隔离

实际生产环境中,我们可能会调用很多函数,每个函数都需要很多局部变量,每个方法都设置局部变量会很不方便。
为了解决这个问题,一个直观的的方法就是建立一个全局字典,保存进程 ID 到该进程局部变量的映射关系,运行中的线程可以根据自己的 ID 来获取本身拥有的数据。这样,就可以避免在函数调用中传递参数,如下示例:

import threading
global_data = {}

def thread_cal():
    global global_data
    cur_thread = threading.current_thread()
    global_data[cur_thread] = 0
    for _ in range(1000):
        global_data[cur_thread] += 1
    print(cur_thread.getName(), global_data[cur_thread])

threads = []
for i in range(10):
    threads.append(threading.Thread(target=thread_cal))
    threads[i].start()

1.这种做法并不完美。首先,每个函数在需要线程局部数据时,都需要先取得自己的线程ID,略显繁琐。
2.更糟糕的是,这里并没有真正做到线程之间数据的隔离,因为每个线程都可以读取到全局的字典,每个线程都可以对字典内容进行更改。

为了更好解决这个问题,python 线程库实现了 ThreadLocal 变量(很多语言都有类似的实现,比如Java)。ThreadLocal 真正做到了线程之间的数据隔离,并且使用时不需要手动获取自己的线程 ID

4.ThreadLocal

import threading
global_data = threading.local()

def thread_cal():
    global_data.num = 0 # 每个线程调取各自的num
    for _ in range(1000):
        global_data.num += 1
    print(threading.current_thread().getName(), global_data.num)

threads = []
for i in range(10):
    threads.append(threading.Thread(target=thread_cal))
    threads[i].start()

print("Main thread: ", global_data.__dict__)
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页