Python封装高性能的G变量

一: 需求

  • 为什么要封装一个G变量?
    • 在进行数据开发的过程中, 我们很多时候需要得到某一个维度的很多变量。而这些变量是通过计算得到的。如果每次都调用方法/发送请求获取这个值, 我们会浪费大量的资源, 去做重复的事情。
  • 如何解决这样的问题?
    • 我们可以将获取的值, 全部存储到一个变量中, 这样如果后续的计算, 再需要这个结果, 我们直接拿来用就好了。

二: 简单的封装G变量

  • 思路:

    • 重构getattr方法, 让使用g.属性的时候, 直接调用方法, 获取到的值,加入字典中, 并将本次的值返回。
    • 方法中/API中,暴露一个字典,让其他三方通过参数的方式可以直接调用内部的方法。
  • method.py代码

from types import FunctionType


def name():
    return "renshanwen"


def age():
    return 18


method_map = dict()
for func in dir():
    if isinstance(eval(func), FunctionType):
        method_map.update({
    
    func: eval(func)})

  • g.py代码
# -*- coding: utf-8 -*-
from methods import method_map


class G(object):

    def __getattr__(self, func_name):
        # 调用方法, 获取值, 并将值赋值给__dict__, 这样满足下次直接使用.属性可以获取到。
        if func_name in method_map.keys():
            result = method_map.get(func_name)()
            self.__dict__[func_name] = result
            return result

    def clean(self):
        self.__dict__ = {
    
    }


g = G()
  • operaters 代码
from g import g


if __name__ == '__main__':
    if g.name == "renshanwen" and g.age == 18:
        print("get var success,  name is {}, age is {}. \n".format(g.name, g.age))
    else:
        print("get var fail. \n")
  • 运行结果:
get var success,  name is renshanwen, age is 18. 

三: 采用协程进行性能优化

  • 存在的问题:

    • 上述代码是存在问题的, 如果我们需要获取G关联的100个属性, 那么我们需要串行的一个一个方法/API的调用, 方法调用还好, 如果是API调用, 那网络延迟是非常影响性能的。因此需要优化。
  • 解决方案:

    • 采用协程, 并行获取G变量的多个属性。
  • g.py增加协程

# -*- coding: utf-8 -*-
import gevent
from methods import method_map
from gevent import monkey

monkey.patch_all()


class G(object):

    def __getattr__(self, func_name):
        # 调用方法, 获取值, 并将值赋值给__dict__, 这样满足下次直接使用.属性可以获取到。
        if func_name in method_map.keys():
            print("方法被调用了")
            result = method_map.get(func_name)()
            self.__dict__[func_name] = result
            return result

    def clean(self):
        self.__dict__ = {
    
    }

    def parallel_req_vars(self, vars_list):
        # 并行请求变量列表
        tasks = [gevent.spawn(self.__getattr__, var) for var in vars_list]
        gevent.joinall(tasks)

g = G()
  • operates.py 进行测试
import time

from g import g


if __name__ == '__main__':
    g.parallel_req_vars(vars_list=["name", "age"])
    time.sleep(2)
    print("在耗时....")
    print(g.name)
    print(g.age)
  • 测试结果
方法被调用了
方法被调用了
在耗时....
renshanwen
18

四: 替换成API调用

  • G变量的getattr进行调整
    def __getattr__(self, func_name):
        # 调用方法, 获取值, 并将值赋值给__dict__, 这样满足下次直接使用.属性可以获取到。
        # 此处换成HTTP/RPC调用即可
        result = rpc('input', func_name)
        self.__dict__[func_name] = result
        return result

五:方法/API调用的时候传入参数

  • 代码调整:
    def __getattr__(self, func_name, **kwargs):
        # 调用方法, 获取值, 并将值赋值给__dict__, 这样满足下次直接使用.属性可以获取到。
        if func_name in method_map.keys():
            result = method_map.get(func_name)(**kwargs)
            self.__dict__[func_name] = result
            return result

猜你喜欢

转载自blog.csdn.net/qq_41341757/article/details/127426871