• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

关于python:Python中Java的InheritableThreadLocal对等实现

python 搞代码 3年前 (2022-02-20) 27次浏览 已收录 0个评论

背景

后端接管到一个用户申请后,在申请其余第三方接口时,须要携带用户申请中的trace_id,以便后续梳理申请链路和定位问题。

原有的代码基于Python的Django框架开发,不同的用户申请之间是线程隔离的,不同用户申请的trace_id天然也不同。除此之外,为了便于读取trace_id所以将其存储为一个全局变量。基于这两点,原代码中采纳threading.local()来存储trace_id。

为了放慢申请速度,须要通过多线程来并发申请第三方接口(PS:也能够应用协程,然而原有的接口调用封装并不反对异步,改变起来工作量太大)。然而因为threading.local()本就是线程隔离的,所以子线程根本无法拿到父线程(申请线程)的trace_id,而后就会呈现报错:'_thread._local' object has no attribute 'trace_id'

在简略的搜寻当前,发现Java中自带InheritableThreadLocal(与ThreadLocal不同,应用InheritableThreadLocal创立的变量的属性能够被子线程继承,以持续应用)。然而不分明为什么Python没有(PS:事实上stackoverflow下面也有发问,然而不晓得为什么没有答复),所以做了一个简略的实现。

代码实现

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import copy
from _threading_local import local
from threading import current_thread, Thread


class InheritableThread(Thread):
    def __init__(self, *args, **kwargs):
        self.parent = current_thread()
        Thread.__init__(self, *args, **kwargs)


def copy_parent_attribute(self):
    """
    :raise AttributeError: parent may not exist
    """

    parent = current_thread().parent
    parent_local = self._local__impl.dicts.get(id(parent))
    if parent_local is not None:
        parent_dicts = parent_local[1]
        for key, value in parent_dicts.items():
            self.__setattr__(key, copy.deepcopy(value))


class InheritableLocal(local):
    """
    Please use InheritableThread to create threads, if you want your son threads can inherit parent threads' local
    """

    def __new__(cls, *args, **kwargs):
        self = local.__new__(cls, *args, **kwargs)
        try:
            copy_parent_attribute(self)
        except AttributeError:
            # Some threads may not be created by InheritableThread
            pass
        return self

    def __getattribute__(self, item):
        try:
            return local.__getattribute__(self, item)
        except AttributeError as e:
            try:
                copy_parent_attribute(self)
                return local.__getattribute__(self, item)
            except AttributeError:
                raise e

    def __delattr__(self, item):
        try:
            return local.__delattr__(self, item)
        except AttributeError as e:
            try:
                copy_parent_attribute(self)
                return local.__delattr__(self, item)
            except AttributeError:
                raise e
  1. 为了可能在子线程中拜访父线程,所以须要在创立子线程时,将父线程记录下来:self.parent = current_thread()
  2. 子线程在构建InheritableLocal()时,依据记录下来的父线程,将父线程中的InheritableLocal()的属性复制过去,因为是InheritableLocal()基于threading.local(),所以这里复制时须要分明threading.local()的构造

threading.local()的构造:

应用办法

thread_ctx = InheritableLocal()
t = InheritableThread(target=function, args=(arg1, arg2, arg3))
t.start()
t.join()
  1. 应用InheritableLocal()代替threading.local()来创立一个线程环境变量,没有其余副作用
  2. 应用InheritableThread()代替Thread()来创立一个线程,同样没有副作用

而后创立进去的子线程就能够继承父线程的环境变量了,当然两个线程之间的环境变量还是互相隔离的,继承只会产生在子线程创立时。

本文由博客一文多发平台 OpenWrite 公布!


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:关于python:Python中Java的InheritableThreadLocal对等实现
喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址