一个管理全局实例的python框架

一个管理全局实例的框架,利用元类(metaclass)和混合类(mixin) 。

1 代码实现

这段代码通过元类和混合类的机制提供了一个可以全局访问且线程安全的单例模式框架。这种设计模式在多线程应用程序中非常有用,尤其是在需要全局管理资源或实例的情况下。

# Copyright (c) OpenMMLab. All rights reserved.
import inspect
import threading
import warnings
from collections import OrderedDict
from typing import Type, TypeVar_lock = threading.RLock()
T = TypeVar('T')def _accquire_lock() -> None:"""Acquire the module-level lock for serializing access to shared data.This should be released with _release_lock()."""if _lock:_lock.acquire()def _release_lock() -> None:"""Release the module-level lock acquired by calling _accquire_lock()."""if _lock:_lock.release()class ManagerMeta(type):"""The metaclass for global accessible class.The subclasses inheriting from ``ManagerMeta`` will manage theirown ``_instance_dict`` and root instances. The constructors of subclassesmust contain the ``name`` argument.Examples:>>> class SubClass1(metaclass=ManagerMeta):>>>     def __init__(self, *args, **kwargs):>>>         passAssertionError: <class '__main__.SubClass1'>.__init__ must have thename argument.>>> class SubClass2(metaclass=ManagerMeta):>>>     def __init__(self, name):>>>         pass>>> # valid format."""def __init__(cls, *args):cls._instance_dict = OrderedDict()params = inspect.getfullargspec(cls)params_names = params[0] if params[0] else []assert 'name' in params_names, f'{cls} must have the `name` argument'super().__init__(*args)class ManagerMixin(metaclass=ManagerMeta):"""``ManagerMixin`` is the base class for classes that have global accessrequirements.The subclasses inheriting from ``ManagerMixin`` can get theirglobal instances.Examples:>>> class GlobalAccessible(ManagerMixin):>>>     def __init__(self, name=''):>>>         super().__init__(name)>>>>>> GlobalAccessible.get_instance('name')>>> instance_1 = GlobalAccessible.get_instance('name')>>> instance_2 = GlobalAccessible.get_instance('name')>>> assert id(instance_1) == id(instance_2)Args:name (str): Name of the instance. Defaults to ''."""def __init__(self, name: str = '', **kwargs):assert isinstance(name, str) and name, \'name argument must be an non-empty string.'self._instance_name = name@classmethoddef get_instance(cls: Type[T], name: str, **kwargs) -> T:"""Get subclass instance by name if the name exists.If corresponding name instance has not been created, ``get_instance``will create an instance, otherwise ``get_instance`` will return thecorresponding instance.Examples>>> instance1 = GlobalAccessible.get_instance('name1')>>> # Create name1 instance.>>> instance.instance_namename1>>> instance2 = GlobalAccessible.get_instance('name1')>>> # Get name1 instance.>>> assert id(instance1) == id(instance2)Args:name (str): Name of instance. Defaults to ''.Returns:object: Corresponding name instance, the latest instance, or rootinstance."""_accquire_lock()assert isinstance(name, str), \f'type of name should be str, but got {type(cls)}'instance_dict = cls._instance_dict  # type: ignore# Get the instance by name.if name not in instance_dict:instance = cls(name=name, **kwargs)  # type: ignoreinstance_dict[name] = instance  # type: ignoreelif kwargs:warnings.warn(f'{cls} instance named of {name} has been created, ''the method `get_instance` should not accept any other ''arguments')# Get latest instantiated instance or root instance._release_lock()return instance_dict[name]@classmethoddef get_current_instance(cls):"""Get latest created instance.Before calling ``get_current_instance``, The subclass must have called``get_instance(xxx)`` at least once.Examples>>> instance = GlobalAccessible.get_current_instance()AssertionError: At least one of name and current needs to be set>>> instance = GlobalAccessible.get_instance('name1')>>> instance.instance_namename1>>> instance = GlobalAccessible.get_current_instance()>>> instance.instance_namename1Returns:object: Latest created instance."""_accquire_lock()if not cls._instance_dict:raise RuntimeError(f'Before calling {cls.__name__}.get_current_instance(), you ''should call get_instance(name=xxx) at least once.')name = next(iter(reversed(cls._instance_dict)))_release_lock()return cls._instance_dict[name]@classmethoddef check_instance_created(cls, name: str) -> bool:"""Check whether the name corresponding instance exists.Args:name (str): Name of instance.Returns:bool: Whether the name corresponding instance exists."""return name in cls._instance_dict@propertydef instance_name(self) -> str:"""Get the name of instance.Returns:str: Name of instance."""return self._instance_name

2 代码详细解析

2.1 导入依赖和初始化锁

import inspect
import threading
from collections import OrderedDict
from typing import Type, TypeVar_lock = threading.RLock()
T = TypeVar('T')
  • inspect 用于获取类和函数的内部信息。
  • threadingRLock 用于同步多线程环境下对数据的访问,以保证线程安全。
  • OrderedDict 保持插入顺序的字典,用于存储实例。
  • TypeVarType 用于类型注解,提高代码的可读性和健壮性。

2.2 锁的获取与释放

def _accquire_lock() -> None:"""Acquire the module-level lock for serializing access to shared data."""if _lock:_lock.acquire()def _release_lock() -> None:"""Release the module-level lock acquired by calling _accquire_lock()."""if _lock:_lock.release()

这两个函数用于在多线程环境中获取和释放锁,确保对共享数据的访问是线程安全的。

2.3 元类 ManagerMeta

class ManagerMeta(type):def __init__(cls, *args):cls._instance_dict = OrderedDict()params = inspect.getfullargspec(cls)params_names = params[0] if params[0] else []assert 'name' in params_names, f'{cls} must have the `name` argument'super().__init__(*args)
  • 这是一个元类,用于创建可以全局访问的类的子类。
  • cls._instance_dict 是一个有序字典,用于存储该类的所有实例。
  • 检查类构造函数中必须包含 name 参数,这是管理不同实例的关键字段。

2.4 混合类 ManagerMixin

class ManagerMixin(metaclass=ManagerMeta):def __init__(self, name: str = '', **kwargs):assert isinstance(name, str) and name, 'name argument must be an non-empty string.'self._instance_name = name@classmethoddef get_instance(cls: Type[T], name: str, **kwargs) -> T:...@classmethoddef get_current_instance(cls):...@classmethoddef check_instance_created(cls, name: str) -> bool:...@propertydef instance_name(self) -> str:...
  • ManagerMixin 是一个使用 ManagerMeta 作为元类的基类,用于实现全局访问和实例管理。
  • __init__ 方法初始化实例,必须提供非空的 name 参数。
  • get_instance 方法根据 name 创建或获取实例。根据 name 检查实例是否存在。如果不存在,则创建一个新实例并添加到 _instance_dict。如果存在,忽略 kwargs 并返回现有实例。
  • get_current_instance 获取最近创建的实例。获取 _instance_dict 中最后创建的实例。
  • check_instance_created 检查是否已创建指定名称的实例。检查 _instance_dict 中是否存在名为 name 的实例。
  • instance_name 属性返回实例名称。

这段代码定义了一个可以全局访问的单例模式的框架,使用元类和混合类(mixin)。为了更好地理解如何使用这个框架,我将给出一个具体的应用示例。

3 示例场景1

假设我们需要创建一个全局配置管理器,这个管理器可以在程序的多个地方被访问和修改,同时确保全局只有一个实例。

3.1 定义配置管理器类

首先,我们利用 ManagerMixinManagerMeta 来定义一个 ConfigurationManager 类。

class ConfigurationManager(ManagerMixin):def __init__(self, name, settings={}):super().__init__(name)self.settings = settingsdef set(self, key, value):"""Set a configuration value."""self.settings[key] = valuedef get(self, key):"""Get a configuration value."""return self.settings.get(key, None)

3.2 使用全局配置管理器

接下来,我们将展示如何在不同部分的代码中创建和访问这个全局的配置管理器实例。在 init(self, name, settings={}) 方法中,name 参数起着关键的作用,它用于标识和区分不同的 ConfigurationManager 实例。这一设计是基于 ManagerMixin 和 ManagerMeta 提供的全局访问和单例管理机制。ManagerMixin 和 ManagerMeta 设计的目的是实现单例模式,即确保每个具有特定名称的类实例是唯一的。这通过内部的 _instance_dict 来管理每个实例的创建和存储实现,其中每个实例都与一个特定的 name 关联。
当你通过 get_instance 方法请求一个实例时,系统会检查是否已经存在一个与提供的 name 相关联的实例。如果存在,它将返回该实例;如果不存在,它将创建一个新实例。

在程序的初始化阶段或配置读取阶段,我们可以创建和初始化 ConfigurationManager 的实例。

# 创建全局配置管理器实例
config_manager = ConfigurationManager.get_instance('global_config', settings={'debug_mode': False})# 修改设置
config_manager.set('api_key', '12345')

在程序的其他部分,我们可以通过名称访问这个已经创建的配置管理器实例,而不需要再次创建它。

# 在另一个文件或模块中访问全局配置管理器
config_manager = ConfigurationManager.get_instance('global_config')
api_key = config_manager.get('api_key')
print(f"API Key: {api_key}")

假设一个应用程序需要连接到两个不同的数据库
这里,production_db 和 development_db 作为 name 的值,标识了两个不同的数据库配置管理器实例。这使得它们可以存储和管理独立的设置,而不会相互干扰。这种方式在实际开发中非常实用,尤其是在大型或复杂的系统中。

db_config_prod = ConfigurationManager.get_instance('production_db', settings={'host': 'prod_host', 'port': 3306})
db_config_dev = ConfigurationManager.get_instance('development_db', settings={'host': 'dev_host', 'port': 3306})

3.3 说明

通过 ManagerMixinManagerMeta 的设计,ConfigurationManager 类保证了即使在复杂的多模块程序中,global_config 的实例也只被创建一次。此外,ManagerMixin 提供的 get_instance 方法使得访问这些全局实例变得简单和一致。

这种方式特别适用于需要跨多个模块共享单个实例的场景,如配置管理、数据库连接管理等。它提供了一种结构化和线程安全的方式来管理全局实例。

4 示例场景2

4.1 代码实现

class MMLogger(Logger, ManagerMixin):"""Formatted logger used to record messages.``MMLogger`` can create formatted logger to log message with differentlog levels and get instance in the same way as ``ManagerMixin``.``MMLogger`` has the following features:- Distributed log storage, ``MMLogger`` can choose whether to save log ofdifferent ranks according to `log_file`.- Message with different log levels will have different colors and formatwhen displayed on terminal.Examples:>>> logger = MMLogger.get_instance(name='MMLogger',>>>                                logger_name='Logger')>>> # Although logger has name attribute just like `logging.Logger`>>> # We cannot get logger instance by `logging.getLogger`.>>> assert logger.name == 'Logger'>>> assert logger.instance_name = 'MMLogger'>>> assert id(logger) != id(logging.getLogger('Logger'))>>> # Get logger that do not store logs.>>> logger1 = MMLogger.get_instance('logger1')>>> # Get logger only save rank0 logs.>>> logger2 = MMLogger.get_instance('logger2', log_file='out.log')>>> # Get logger only save multiple ranks logs.>>> logger3 = MMLogger.get_instance('logger3', log_file='out.log',>>>                                 distributed=True)Args:name (str): Global instance name.logger_name (str): ``name`` attribute of ``Logging.Logger`` instance.If `logger_name` is not defined, defaults to 'mmengine'.log_file (str, optional): The log filename. If specified, a``FileHandler`` will be added to the logger. Defaults to None.log_level (str): The log level of the handler. Defaults to'INFO'. If log level is 'DEBUG', distributed logs will be savedduring distributed training.file_mode (str): The file mode used to open log file. Defaults to 'w'.distributed (bool): Whether to save distributed logs, Defaults tofalse.file_handler_cfg (dict, optional): Configuration of file handler.Defaults to None. If ``file_handler_cfg`` is not specified,``logging.FileHandler`` will be used by default. If it isspecified, the ``type`` key should be set. It can be``RotatingFileHandler``, ``TimedRotatingFileHandler``,``WatchedFileHandler`` or other file handlers, and the remainingfields will be used to build the handler.Examples:>>> file_handler_cfg = dict(>>>    type='TimedRotatingFileHandler',>>>    when='MIDNIGHT',>>>    interval=1,>>>    backupCount=365)`New in version 0.9.0.`"""def __init__(self,name: str,logger_name='mmengine',log_file: Optional[str] = None,log_level: Union[int, str] = 'INFO',file_mode: str = 'w',distributed=False,file_handler_cfg: Optional[dict] = None):Logger.__init__(self, logger_name)ManagerMixin.__init__(self, name)# Get rank in DDP mode.if isinstance(log_level, str):log_level = logging._nameToLevel[log_level]global_rank = _get_rank()device_id = _get_device_id()# Config stream_handler. If `rank != 0`. stream_handler can only# export ERROR logs.stream_handler = logging.StreamHandler(stream=sys.stdout)# `StreamHandler` record month, day, hour, minute, and second# timestamp.stream_handler.setFormatter(MMFormatter(color=True, datefmt='%m/%d %H:%M:%S'))# Only rank0 `StreamHandler` will log messages below error level.if global_rank == 0:stream_handler.setLevel(log_level)else:stream_handler.setLevel(logging.ERROR)stream_handler.addFilter(FilterDuplicateWarning(logger_name))self.handlers.append(stream_handler)@classmethoddef get_current_instance(cls) -> 'MMLogger':"""Get latest created ``MMLogger`` instance.:obj:`MMLogger` can call :meth:`get_current_instance` before anyinstance has been created, and return a logger with the instance name"mmengine".Returns:MMLogger: Configured logger instance."""if not cls._instance_dict:cls.get_instance('mmengine')return super().get_current_instance()业务代码中使用
if not MMLogger.check_instance_created('OpenCompass'):logger = MMLogger.get_instance('OpenCompass',logger_name='OpenCompass',log_level=log_level)
else:logger = MMLogger.get_instance('OpenCompass')

4.2 代码解释

这段代码定义了一个 MMLogger 类,继承自 Logger 类和 ManagerMixin 混合类。MMLogger 用于创建格式化的日志记录器,具有全局实例管理功能,并支持不同日志级别的消息记录。这个类增加了多个特性,包括分布式日志存储和终端彩色显示等。以下是详细的解释:

MMLogger 类定义与功能

  • MMLogger 结合了 Logger 的日志功能和 ManagerMixin 的全局实例管理能力。
  • 它支持不同的日志级别,并且可以根据配置将日志存储到不同的文件中。
  • 日志消息可以在终端以不同的颜色和格式显示,提高日志的可读性。

构造函数 (init)

  • 参数解释

    • name: 全局实例名称,用于通过 ManagerMixin 管理。
    • logger_name: Logger 实例的名称,默认为 “mmengine”。
    • log_file: 如果指定,日志将被写入到这个文件中。
    • log_level: 日志级别,默认为 “INFO”。
    • file_mode: 文件打开模式,默认为 ‘w’,表示写模式。
    • distributed: 是否保存分布式日志,默认为 False
    • file_handler_cfg: 文件处理配置,用于创建不同类型的 FileHandler
  • 实现细节

    • 首先,根据 logger_name 初始化 Logger 基类。
    • 调用 ManagerMixin 的初始化函数,设置实例名。
    • 根据 log_level 的字符串表示转换为对应的日志级别数值。
    • 获取当前设备的全局排名 (global_rank) 和设备 ID (device_id),用于分布式日志记录。
    • 根据 global_rank 配置 stream_handler,只有在全局排名为 0 的设备上,才会记录低于错误级别的日志。
    • 如果指定了 log_file,将根据是否是分布式环境来配置文件名,包括主机名和排名等信息。
    • 根据 file_handler_cfg 配置或创建默认的 FileHandler,并设置格式化器和日志级别。

类方法和属性

  • get_current_instance: 获取最近创建的 MMLogger 实例。如果没有实例被创建,它会首先通过默认名称 “mmengine” 创建一个实例。

用法示例

  • MMLogger.get_instance 方法用于获取或创建 MMLogger 的实例,确保每个实例名称对应唯一的日志记录器对象。
  • 使用 MMLogger 记录的日志不受第三方日志配置的影响,这通过实例管理和专用的获取方法来保证。
  • 日志文件可以根据是否是分布式训练来分别保存,支持复杂的文件处理配置。

cls._instance_dict的说明

instance_dict = cls._instance_dict这段代码的意思是从类 cls 中获取 _instance_dict 属性,并将其赋值给本地变量 instance_dict。这里的 _instance_dict 是一个类属性,通常用于存储与该类相关的一些实例数据。

ManagerMixin 类中,_instance_dict 被用作一个有序字典(OrderedDict),用来存储该类的所有实例。这允许类通过名字快速访问其任意实例,实现了一种全局访问和管理的模式。cls._instance_dict 通常在类方法中被访问或修改,如创建新实例、获取实例、检查实例是否已创建等。

ManagerMixin 的类方法 get_instance 中,cls._instance_dict 被用来检查一个具有特定名称的实例是否已存在。如果存在,则返回该实例;如果不存在,则创建一个新实例,将其添加到 _instance_dict 中,然后返回新创建的实例。这种方式确保了每个实例的唯一性,并允许全局管理。

get_instance 方法用于获取名为 name 的实例。如果这个名字的实例不存在,方法会创建一个新的实例并将其添加到 _instance_dict 中。

为何需要 MMLogger(Logger, ManagerMixin)

在Python中,logging.Logger 类本身并不是单例模式。虽然 logging.getLogger(name) 能保证同一个 name 返回相同的 Logger 实例,但这是通过内部维护一个字典实现的,而不是真正意义上的单例模式。Logger 实例可以多次创建并拥有不同的配置,这意味着不同的地方可能会创建具有不同行为的相同名称的 Logger 实例。

MMLogger 类继承自 Logger 并混合使用了 ManagerMixin,这样的设计是为了解决以下几个方面的需求:

  1. 增强的单例管理

    • ManagerMixin 提供了一个基于名称的实例管理机制,确保全局只有一个唯一的实例,即使是在不同的模块和组件中也是如此。
    • 这种管理方式使得 MMLogger 可以在整个应用程序中共享和访问,无论是在哪个模块中创建。
  2. 定制化和独立性

    • 使用 MMLogger 允许开发者对日志系统进行定制化配置,而不受默认 logging 模块的全局配置的影响。例如,可以实现高度定制的格式化器、处理器和过滤器。
    • 它可以避免第三方库或其他模块中的日志配置对自己应用的影响。
  3. 分布式日志功能

    • MMLogger 设计了分布式日志功能,能够根据运行环境(如不同的服务器或处理器)自动调整日志的存储和显示。这在大规模分布式应用程序中非常有用,特别是在机器学习或数据处理等领域。
  4. 日志的动态配置

    • MMLogger 通过 ManagerMixin 提供的 get_instance 方法允许动态创建或获取日志实例,并且可以为不同的日志实例设置不同的文件路径、日志级别等参数。
    • 这使得日志系统的扩展性和灵活性大大提高,能够满足不同场景下的需求。

总结

虽然 logging.getLogger(name) 提供了一种方便的方式来复用 Logger 实例,但它并没有实现真正意义上的单例模式,因为 Logger 的配置是可变的,且可以在不同的上下文中被修改,导致潜在的配置冲突和行为不一致。这种设计在灵活性方面有优势,允许对 Logger 进行细粒度的配置,但也需要开发者在大型应用中仔细管理日志配置,以避免意外的行为。假设在一个大型应用程序中,有两个模块都使用名为 “MyApp” 的 Logger。在模块A中,可能设置了将日志输出到控制台的处理器,而在模块B中,则可能添加了一个将日志写入文件的处理器。如果模块A先于模块B执行,那么在模块B执行时,“MyApp” 的 Logger 实例已经包含了一个输出到控制台的处理器,这可能不是模块B期望的行为。
MMLogger 的设计旨在提供更加强大和灵活的日志管理能力,通过 ManagerMixin 实现更严格的单例控制,以及通过继承和扩展 Logger 提供的功能来满足特定的业务需求。这种设计模式在需要高度定制化和在多个地方需要访问同一日志实例的应用中尤为重要。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/25185.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT系列教程(9) 主窗口学习

简介 任何界面应用都有一个主窗口&#xff0c;今天我们谈谈主窗口相关知识。一个主窗口包括菜单栏&#xff0c;工具栏&#xff0c;状态栏&#xff0c;以及中心区域等部分。我们先从菜单栏说起 菜单栏 我们创建一个主窗口应用程序, 在ui文件里的菜单栏里有“在这里输入”的一个…

windows安装conda

1 Conda简介 Conda 是一个开源的软件包管理系统和环境管理系统&#xff0c;用于安装多个版本的软件包及其依赖关系&#xff0c;并在它们之间轻松切换。Conda 是为 Python 程序创建的&#xff0c;适用于 Linux&#xff0c;OS X 和Windows&#xff0c;也可以打包和分发其他软…

Web前端放图片位置:深入探索与最佳实践

Web前端放图片位置&#xff1a;深入探索与最佳实践 在Web前端开发中&#xff0c;图片作为重要的视觉元素&#xff0c;其放置位置往往影响着网页的整体布局和用户体验。然而&#xff0c;如何合理地放置图片&#xff0c;以最大化其视觉效果并提升用户体验&#xff0c;却是一个颇…

mnist的t-SNE二维空间可视化MATLAB

%% filename ‘mnist’; digitDatasetPath fullfile(matlabroot,‘toolbox’,‘nnet’,‘nndemos’, … ‘nndatasets’,‘DigitDataset’); imds imageDatastore(digitDatasetPath, … ‘IncludeSubfolders’,true,‘LabelSource’,‘foldernames’); %% labelCount coun…

【清华大学】《自然语言处理》(刘知远)课程笔记

自然语言处理基础&#xff08;Natural Language Processing Basics, NLP Basics&#xff09; 自然语言处理( Natural Language Processing, NLP)是计算机科学领域与人工智能领域中的一个重要方向。它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。自然语言…

RN:Error: /xxx/android/gradlew exited with non-zero code: 1

问题 执行 yarn android 报错&#xff1a; 解决 这个大概率是缓存问题&#xff0c;我说一下我的解决思路 1、yarn doctor 2、根据黄色字体提示&#xff0c;说我包版本不对&#xff08;但是这个是警告应该没事&#xff0c;但是我还是装了&#xff09; npx expo install --…

进军rust:从0开始学习rust语法

一.变量类型 Rust语言中的基础数据类型有以下几种&#xff1a; 1.整数型 整数型简称整型&#xff0c;按照比特位的长度和有无符号位可以分为以下几种 isize和usize两种整数类型是用来衡量数据大小的&#xff0c;它们的位长度取决于所运行的目标平台&#xff0c;如果是32位架…

Springboot+Vue的网上购物商城系统(前后端分离)

技术栈 JavaSpringBootMavenMySQLMyBatisVueShiroElement-UI 角色对应功能 用户商家 功能截图

Linux服务器配置一个简单的DNS

配置一个简单的DNS服务器可以使用BIND (Berkeley Internet Name Domain)。 配置DNS的步骤如下 一、安装BIND sudo apt-update sudo apt-get install bind9 二、配置BIND。 编辑 /etc/bind/named.conf.local 文件&#xff0c;添加一个简单的zone配置 zone "example.c…

【机器学习】基于图注意力网络(GAT)的Cora数据集论文主题预测

1. 引言 1.1. GAT概述 GAT是一种基于图神经网络的深度学习模型&#xff0c;专门用于处理图结构数据。与传统的神经网络不同&#xff0c;GAT能够直接对图结构数据进行学习和推理&#xff0c;通过捕捉和传递节点之间的关系和特征信息&#xff0c;实现对图结构数据的深度分析和挖…

GPU风扇不旋转:为什么会发生这种情况以及如何修复

GPU在处理数百万像素时往往会发热,因此冷却风扇静音可能会令人担忧,这是可以理解的!如果你注意到你的GPU风扇没有旋转,下面是如何评估是否存在真正的问题,以及如何解决问题。 风扇停止旋转可能是一个功能,而不是一个Bug 如果GPU没有用于密集任务或没有达到高温,则可以…

使用Spring Boot实现Redis多数据库缓存

Redis多数据库存储实现用户行为缓存 在我的系统中&#xff0c;为了优化用户行为数据的存储与访问效率&#xff0c;我引入了Redis缓存&#xff0c;并将数据分布在不同的Redis数据库中。通过这种方式&#xff0c;可以减少单一数据库的负载&#xff0c;提高系统的整体性能。 主要…

GEE案例——利用MODIS数据(NDVI)计算中国大陆2000-2023年的MK、Sens趋势性分析和Z值统计以及方差分析

简介 利用MODIS数据(NDVI)计算2000-2023年中国大陆的MK、Sens趋势性分析和Z值统计以及方差分析 流程 要进行NDVI数据的趋势性分析和统计分析,需要按照以下步骤进行: 1. 数据准备:获取2000-2023年的MODIS NDVI数据,可以从NASA的MODIS数据网站或其他可靠的数据来源获取…

yarn保姆级安装和使用

目录 前言 一、yarn简介 主要特性 使用场景 二、yarn的安装 yarn的下载 配置环境变量 三、yarn的常用命令 四、yarn的常用配置项 五、npm与yarn的区别 前言 本文旨在介绍如何安装和使用Yarn&#xff0c;以及它的一些常见用法。我们将从Yarn的基本概念开始&#xff0c;…

使用try-with-resources语句替代try-finally语句

Java类库中包含许多必须通过调用close方法手动关闭的资源&#xff0c;例如InputStream、OutputStream和java.sql.Connection。 开发人员经常忽视关闭资源&#xff0c;其性能结果可想而知。 从以往来看&#xff0c;try-finally语句是保证资源正确关闭的最佳方式&#xff0c;即使…

Web前端的规划:深度解构与未来展望

Web前端的规划&#xff1a;深度解构与未来展望 在数字化浪潮汹涌的时代&#xff0c;Web前端作为用户与互联网世界的桥梁&#xff0c;其重要性不言而喻。对于前端开发者而言&#xff0c;一份精心规划的Web前端策略&#xff0c;不仅是项目成功的基石&#xff0c;更是技术进步的引…

Foundation Model 通用大模型的评测体系

随着大模型评测需求逐渐增加,相关研究也进一步深入。大模型相比传统模 型&#xff0c;泛化能力更强、灵活性更高、适应性更广&#xff0c;多任务、多场景&#xff0c;评测维度、评测指标和数 据集更复杂&#xff0c;面向大模型的评估方法、评测基准、测试集成为新的研究课题。 …

Qt图表类介绍

本文主要介绍QCharts相关的模块及类。 Qt中图表模块有以下几种类型&#xff1a;折线图&#xff0c;样条曲线图&#xff0c;面积图&#xff0c;散点图&#xff0c;条形图&#xff0c;饼图&#xff0c;方块胡须图&#xff0c;蜡烛图&#xff0c;极坐标图。 QCharts的图表框架类似…

数据Ant-Design-Vue动态表头并填充

Ant-Design-Vue是一款基于Vue.js的UI组件库&#xff0c;广泛应用于前端开发中。在Ant-Design-Vue中&#xff0c;提供了许多常用的组件&#xff0c;包括表格组件。表格组件可以方便地展示和处理大量的数据。 在实际的开发中&#xff0c;我们经常会遇到需要根据后台返回的数据动…

【Python】Selenium基础入门

Selenium基础入门 一、Selenium简介二、Selenium的安装三、Selenium的使用1.访问web网站2.元素定位根据标签 id 获取元素根据标签 name 属性的值获取元素根据 Xpath 语句获取元素根据标签名获取元素根据CSS选择器获取元素根据标签的文本获取元素&#xff08;精确定位&#xff0…