Python WorkerThread设计实现

WorkerThread 设计

具体细节

threading.local

local的用法:

  • 可以通过设置简单threading.local,并设置相应的LocalManager来管理local
  • 还可以继承自local class, 这种方法可以很有效的实现local的默认值, 方法, 初始化. 注意如果定义了 __init__ 函数, 将会在每个特定的线程中进行 __init__函数的调用,这对于初始化每一个线程的字典来说非常的重要
  • threading.local() :类表示线程本地变量. 线程本地变量对于特定的线程不同. 管理线程本地变量threading.local, 如 mydata = threading.local() mydata.x = 1

继承自threading.local的用法如下(具体见官方源码):

class MyLocal(local):
    number = 2
    initialized = False
    def __init__(self, **kw):
        if self.initialized:
            raise SystemError('__init__ called two many times')
        self.initialized = True
        self.__dict__.update(kw)

    def squared(self):
        return self.number**2

subclasses 可以定义 __slots__, 但是并不是线程本地变量, 而是通过线程共享

LocalManager

LocalManager :该类用来管理本地线程变量,中的具体字段.

class LocalManager(object):


    def __init__(self, local_obj):
        self.local_obj = local_obj

    def to_dict(self):
        rv = {}
        for field in self.fields:
            rv[field] = getattr(self, field, None)
        return rv

    def update(self, **kwargs):
        for field, value in kwargs.iteritems():
            setattr(self, field, value)

    def clear(self):
        self.local_obj.__dict__.clear()

    def __getattr__(self, name):
        return getattr(self.local_obj, name, None)

    def __setattr__(self, name, value):
        if name in self.fields:
            return setattr(self.local_obj, name, value)
        else:
            super(LocalManager, self).__setattr__(name, value)

创建本地线程变量
worker_local = LocalManager(_local) 仅仅这样用, 对于不同的线程, 其中的 worker_local不同

WorkerThread

WorkerThread :该类继承自 threading.Thread, 为具体线程的类

  • threading.Thread 特定用法:
    • 在构造函数中传入一个callable对象,(函数或者其他)
    • 在子类中重写 __init__run 方法
  • get_result(self) 方法类似与 requests.raise_for_status(): 先存异常状态码,再抛出异常
class WorkerThread(threading.Thread):

    def __init__(self, func, *args, **kwargs):
        super(WorkerThread, self).__init__()
        self.func = func
        self.args = args
        self.kwargs = kwargs
        self.exception = None
        self.result = None
        self.request_params = worker_local.to_dict()

    def run(self):
        worker_local.update(**self.request_params)
        try:
            self.result = self.func(*self.args, **self.kwargs)
        except Exception as e:
            self.exception = e
            log_exception('worker', e)

    def get_result(self):
        if self.exception is not None:
            raise self.exception
        else:
            return self.result

注意

  • 在python中对于真正的并行, 应当使用multiprocessing模块, fork多个进行来并行的执行, 因为python 全局解释器锁的存在, python的线程提供interleving交叉, 但是实际上是连续串行执行,这仅仅对于有I/O操作时有效.
  • Thread-local 保存了线程拥有的局部变量,实现了线程变量的隔离, 比较好的实现,可以参考werkzeug中Thread-local的实现, 可以支持协程之间的私有数据 werkzeug

Reference

深入理解Thread-local

你可能感兴趣的:(python)