Python3 - 多线程 - threading 模块(基于win系统)- local组件

目录

一、local 简单介绍

1-1 不使用local组件存在的弊端

二、Local组件的简单使用 - local对象.变量名 = 赋值

2-1 自定义字典实现Local的操作

2-2 基于面对对象实现Local

2-3 基于魔法方法实现Local

2-4 基于魔法方法实现单独存储空间的Local

三、实现Local并使其兼容线程和协程 - 参考Flask源码


一、local 简单介绍

python3 - 多线程 - threading 模块(基于win系统)- Thread、Timer 组件

当多个线程修改同一个数据时,将该数据复制多份给每个线程单独使用,即为每个线程开辟一块空间进行数据存储

1-1 不使用local组件存在的弊端

多个线程同时操作同一个全局变量,每次操作都会修改值,存在锁机制。导致每个线程取到的起始数据不相同,导致最后结果输出错误。

# 未使用local
from threading import Thread
import time

test= -1
def task(arg):
    global test
    test= arg
    # 模拟IO操作,用于实现对全局变量的混乱操作
    time.sleep(2)
    print(test)

for i in range(10):
    t = Thread(target=task,args=(i,))
    t.start()

'''
9
9
9
9
9
9
9
9
9
9
'''

二、Local组件的简单使用 - local对象.变量名 = 赋值

总结:由Local组件的简单使用可以看出Local操作类似于字典的操作。

from threading import Thread
from threading import local
import time
from threading import get_ident # get_ident用于获取线程、进程ID号

# 初始化local对象
loc= local()

def task(arg):
    # 对象.val = 1/2/3/4/5
    loc.value = arg
    time.sleep(2)
    print(loc.value)

for i in range(10):
    t = Thread(target=task,args=(i,))
    t.start()

'''
3
1
0
2
5
4
7
6
9
8
'''

2-1 自定义字典实现Local的操作

from threading import get_ident,Thread
import time

storage = {}

def set(k,v):
    ident = get_ident()
    if ident in storage:
        storage[ident][k] = v
    else:
        storage[ident] = {k:v}

def get(k):
    ident = get_ident()
    return storage[ident][k]

def task(arg):
    set('val',arg)
    v = get('val')
    print(v)

for i in range(10):
    t = Thread(target=task,args=(i,))
    t.start()

2-2 基于面对对象实现Local

from threading import get_ident,Thread
import time

class Local(object):
    storage = {}
    def set(self, k, v):
        ident = get_ident()
        if ident in Local.storage:
            Local.storage[ident][k] = v
        else:
            Local.storage[ident] = {k: v}
    def get(self, k):
        ident = get_ident()
        return Local.storage[ident][k]

obj = Local()

def task(arg):
    obj.set('val',arg) 
    v = obj.get('val')
    print(v)

for i in range(10):
    t = Thread(target=task,args=(i,))
    t.start()

2-3 基于魔法方法实现Local

from threading import get_ident,Thread
import time

class Local(object):
    storage = {}
    def __setattr__(self, k, v):
        ident = get_ident()
        if ident in Local.storage:
            Local.storage[ident][k] = v
        else:
            Local.storage[ident] = {k: v}
    def __getattr__(self, k):
        ident = get_ident()
        return Local.storage[ident][k]

obj = Local()

def task(arg):
    obj.val = arg
    print(obj.val)

for i in range(10):
    t = Thread(target=task,args=(i,))
    t.start()

2-4 基于魔法方法实现单独存储空间的Local

from threading import get_ident,Thread
import time

class Local(object):
    def __init__(self):
        object.__setattr__(self,'storage',{})
    def __setattr__(self, k, v):
        ident = get_ident()
        if ident in self.storage:
            self.storage[ident][k] = v
        else:
            self.storage[ident] = {k: v}
    def __getattr__(self, k):
        ident = get_ident()
        return self.storage[ident][k]

obj = Local()

def task(arg):
    obj.val = arg
    obj.xxx = arg
    print(obj.val)

for i in range(10):
    t = Thread(target=task,args=(i,))
    t.start()

三、实现Local并使其兼容线程和协程 - 参考Flask源码

try:
    from greenlet import getcurrent as get_ident
except Exception as e:
    from threading import get_ident
from threading import Thread

import time

class Local(object):
    def __init__(self):
        object.__setattr__(self,'storage',{})
    def __setattr__(self, k, v):
        ident = get_ident()
        if ident in self.storage:
            self.storage[ident][k] = v
        else:
            self.storage[ident] = {k: v}
    def __getattr__(self, k):
        ident = get_ident()
        return self.storage[ident][k]

obj = Local()

def task(arg):
    obj.val = arg
    obj.xxx = arg
    print(obj.val)

for i in range(10):
    t = Thread(target=task,args=(i,))
    t.start()

猜你喜欢

转载自blog.csdn.net/qq_33961117/article/details/87645427
今日推荐