当前位置: 首页 > news >正文

Flyte工作流平台调研(五)——扩展集成

系列文章:

Flyte工作流平台调研(一)——整体架构

Flyte工作流平台调研(二)——核心概念说明

Flyte工作流平台调研(三)——核心组件原理

Flyte工作流平台调研(四)——服务部署

Flyte工作流平台调研(五)——扩展集成

Flyte工作流平台调研(六)——跟Ray框架对比

Flyte工作流平台调研(七)——核心源码走读

正文:

Flyte的设计具有高度的可扩展性,可以通过多种方式进行定制。这是官方提供的贡献开发一个集成的样例文档。

以下是Flyte主要的几种集成方式:

Flytekit plugins

简介

Flytekit是Flyte提供的Python SDK,帮助用户使用Python编程设计新的Workflow。它可以解析Python代码,将其编译为有效的工作流DAG,并将其提交给Flyte执行。

Flytekit plugins就是指用户通过 Python 编写自定义代码,来增强 Flytekit(Flyte 的 Python SDK)的功能。通过这种方式,能在 Flyte 工作流(Workflow)中添加自定义任务(Task)、数据处理步骤或其他功能。

插件运行时,基本上直接依赖Python代码或者基础镜像,而不依赖其他服务。

1. Flytekit 插件的作用

Flytekit 插件允许用户在 Flyte 中集成外部工具、服务或库,或在 Flyte 的任务和工作流中引入自定义的执行逻辑。这些插件可以帮助 Flyte 执行各种类型的作业,例如运行特定的机器学习平台、数据库操作、数据验证等。

例如:

  • 通过 Comet 插件,Flyte 工作流可以与 Comet.ml 进行集成,自动追踪机器学习实验。
  • 通过 MLFlow 插件,Flyte 可以追踪和记录机器学习模型的训练过程。

2. Flytekit 插件的特点

  • 纯 Python 实现:Flytekit 插件完全使用 Python 编写,这使得用户可以轻松地开发、测试和调试插件功能。
  • 单元测试:用户可以在本地进行单元测试,确保插件功能的正确性,而无需依赖 Flyte 的集群或其他外部服务。
  • 扩展 Flytekit:插件主要用于扩展 Flytekit 的功能。比如,用户可以编写插件来处理特定的任务,或将 Flyte与特定的服务(如 Comet、MLFlow)集成。

3. 插件的类型

Flytekit 插件可以分为几种类型,根据它们的功能和目标服务进行分类:

  • 机器学习平台插件:如 CometMLFlow,这些插件允许在 Flyte 中直接集成和使用机器学习平台,用于模型追踪、实验管理等。
  • 数据处理插件:如 Great ExpectationsPandera,用于验证数据质量、进行数据验证等操作。
  • 数据库和查询插件:如 DoltDuckDBSQL 插件,提供数据存储、数据库查询等功能。
  • 服务集成插件:如 AWS SageMakerAirflow,这些插件允许将 Flyte 与 AWS 服务或其他外部系统(如 Airflow、BigQuery)集成,进行模型推理、任务执行等。

实现方式

本文档以Flyte的SQLAlchemy这个插件为例进行说明。具体实现一个自定义插件的方式是:

1. 下载Flytekit的代码:

Flytekit的代码仓库地址:GitHub - flyteorg/flytekit: Extensible Python SDK for developing Flyte tasks and workflows. Simple to get started and learn and highly extensible.

代码主要路径:

说明:flytekit是核心源码的实现,plugins是插件的实现。

2. 在代码中实现插件具体的代码

1)创建在plugins路径中创建对应的插件包,比如:

2)在代码中实现自定义的task或者workflow(这个插件只有task)

3)定义自定义task的自定义配置

4)定义运行当前Task的工作流Pod(也就是一个Node)默认依赖的镜像

3. 构建插件依赖的镜像

如果第1步中默认的镜像不是镜像仓库中已经存在的镜像,还需要自己构建当前自定义task的镜像,并上传到镜像仓库。

4. 构建并发布插件

使用项目根目录下创建 setup.py,用于打包插件:

from setuptools import setup, find_packagessetup(name="my_flytekit_plugin",version="0.1.0",description="A custom Flytekit plugin",author="Your Name",packages=find_packages(),install_requires=["flytekit", "requests"],
)

构建并安装插件:

pip install .

将插件发布到 PyPI,便于其他 Flyte 用户使用:

python setup.py sdist bdist_wheel
twine upload dist/*

使用方式

还是以Flyte的SQLAlchemy这个插件为例进行说明。

1. 安装 Flyte 的 SQLAlchemy 插件

pip install flytekitplugins-sqlalchemy

导入所需的库:

from flytekit import kwtypes, task, workflow
from flytekit.types.schema import FlyteSchema
from flytekitplugins.sqlalchemy import SQLAlchemyConfig, SQLAlchemyTask

2. 定义 SQLAlchemy Task

首先,定义一个 SQLAlchemyTask,它将从 RNA 中央数据库的 rna 表返回前 n 条记录。由于该数据库是公共的,可以将数据库 URI 硬编码在字符串中,包括用户名和密码。

注意:
SQLAlchemyTask 的输出默认是  FlyteSchema
警告:
切勿存储用于私有或敏感数据库的密码!
DATABASE_URI = "postgresql://reader:NWDMCE5xdipIjRrp@hh-pgsql-public.ebi.ac.uk:5432/pfmegrnargs"# 定义查询的输出 schema,我们稍后在 `get_mean_length` 任务中复用
DataSchema = FlyteSchema[kwtypes(sequence_length=int)]sql_task = SQLAlchemyTask("rna",query_template=""" select len as sequence_length from rna where len >= {{ .inputs.min_length }} and len <= {{ .inputs.max_length }} limit {{ .inputs.limit }}""",inputs=kwtypes(min_length=int, max_length=int, limit=int),output_schema_type=DataSchema,task_config=SQLAlchemyConfig(uri=DATABASE_URI),
)

3. 定义计算平均长度的任务

接下来,定义一个任务,用于计算我们查询返回的 RNA 序列子集的平均长度。注意,如果你在 Flyte 后端中运行此任务(通过 pyflyte run),如果没有指定镜像,pyflyte run 会使用默认的 flytekit 镜像。默认的 flytekit 镜像没有安装 sqlalchemy 插件。为了正确启动此任务的执行,需要使用以下命令。

bash
复制代码
pyflyte --config ~/.flyte/your-config.yaml run --destination-dir /app --remote --image ghcr.io/flyteorg/flytekit:py3.8-sqlalchemy-latest integrations/flytekit_plugins/sql/sql_alchemy.py my_wf --min_length 3 --max_length 100 --limit 50 
另外,添加了  destination-dir 参数,因为  pyflyte run 默认会将代码复制到  /root 目录,而该镜像的工作目录被设置为  /app
@task
def get_mean_length(data: DataSchema) -> float:dataframe = data.open().all()return dataframe["sequence_length"].mean().item()

4. 将任务组合成一个工作流

最后,将所有任务组合成一个工作流:

@workflow
def my_wf(min_length: int, max_length: int, limit: int) -> float:return get_mean_length(data=sql_task(min_length=min_length, max_length=max_length, limit=limit))

运行代码

if __name__ == "__main__":print(f"Running {__file__} main...")print(my_wf(min_length=50, max_length=200, limit=5))

这样就完成了一个基于 SQLAlchemy 的 Flyte 工作流,能够从公共 PostgreSQL 数据库中查询 RNA 序列的长度,并计算这些序列的平均长度。

Native backend plugins

简介

原生后端插件是指直接依赖 Flyte 的原生计算和编排能力(通常是 Kubernetes 集群中的工作负载),无需额外的外部服务支持。这种插件由 Flyte 的内部组件(如 FlytePropeller 和 Kubernetes)协同管理,用于运行特定类型的工作负载或任务。

比如Native backend的Spark 插件,支持执行Spark Task,使用这种插件时,执行Spark Task时,会先直接在Flyte的k8s集群中启动一个Spark集群,然后再启动Task Pod去访问这个Spark集群执行 Task的具体内容。Spark Task Pods和Spark Cluster Pods都是FlytePropeller启动的,而FlytePropeller具有启动Spark Cluster Pods的能力就是这个插件扩展的,这个插件集成在FlytePropeller中,调用Spark的k8s operator启动一个Spark集群。

主要插件类型

  • 分布式训练
    • Kubeflow PyTorch:运行 PyTorch 分布式训练任务。
    • Kubeflow TensorFlow:运行 TensorFlow 分布式训练任务。
    • MPI Operator:运行基于 Horovod 的深度学习训练任务。
  • 大数据处理
    • Kubernetes Cluster Spark:运行 Spark 作业。
    • Kubernetes Cluster Dask:运行 Dask 作业。
  • 灵活任务
    • Kubernetes Pods:运行任意 Kubernetes Pod 工作负载。
    • Ray:运行 Ray 分布式作业。

主要作用

Native Backend Plugins 的主要作用是提供一种无缝的方式,使用 Kubernetes 原生能力执行特定类型的工作负载,同时保持对 Flyte 工作流的高度集成。以下是其具体作用:

  1. 高效资源管理
    Flyte 利用 Kubernetes 的资源调度能力,根据任务的资源需求动态分配和管理资源(如 CPU、内存、GPU)。
  2. 分布式任务支持
    原生插件支持常见的分布式计算框架(如 PyTorch、TensorFlow、Spark、Ray),简化了大规模分布式任务的开发和运行。
  3. 统一工作流编排
    无需外部服务支持,用户可以将各种任务类型统一集成到 Flyte 的工作流中,实现端到端的数据处理和模型训练。
  4. 简化操作和维护
    通过 Kubernetes 的原生能力,Native Backend Plugins 避免了对外部服务的依赖,简化了部署和运维。

使用方式

这里以一个Ray插件为例,通过Flyte的Ray插件提交一个Ray任务。

1. flytekitplugins-ray基本说明

KubeRay 是一个开源工具包,旨在简化在 Kubernetes 上运行 Ray 应用程序的过程。它提供了一系列工具,增强了在 Kubernetes 上运行和管理 Ray 的操作能力。

插件的关键组件:

  • Ray Operator
  • 用于集群资源创建和删除的后台服务
  • 管理 CRD(Custom Resource Definition)对象的 kubectl 插件/命令行工具
  • 与集群功能无缝集成的作业(Jobs)和服务(Serving)功能

2. 安装插件

pip install flytekitplugins-ray

3. 如果直接给已存在的Ray集群提交任务

@ray.remote
def f(x):return x * x@task(task_config=RayJobConfig(address=<RAY_CLUSTER_ADDRESS>runtime_env={"pip": ["numpy", "pandas"]})
)
def ray_task() -> typing.List[int]:futures = [f.remote(i) for i in range(5)]return ray.get(futures)

4. 使用插件通过Flyte,提交一个Ray任务,并且Ray集群也有Flyte管理

@task(task_config=RayJobConfig(worker_node_config=[WorkerNodeConfig(group_name="test-group", replicas=10)]))
def ray_task() -> typing.List[int]:futures = [f.remote(i) for i in range(5)]return ray.get(futures)

5. 在 Flyte 集群上运行示例

要在 Flyte 集群上运行上述示例,使用以下命令:

pyflyte run --remote ray_example.py \ray_workflow --n 10

此命令将远程运行 ray_example.py 脚本中的 ray_workflow,并传递参数 --n 10。Flyte会先通过KubeRay在自己的K8S集群中创建一个Ray Cluster,然后再运行一个Pod把Ray任务提交到这个Ray Cluster中。

Flyte Agent

简介

Flyte Agent 是一种 长时间运行的无状态服务,通过 gRPC 接收执行请求,并与适当的外部或内部服务交互以启动任务。它的功能定位在支持特定类型的任务,并通过插件化扩展为不同的服务场景。

简单来说,就是在Flyte的K8S集群中启动一个无状态的Agent Pod,执行这种类型的任务时,这个Agent Pod给真正的服务转发请求。

1. 基本的工作流程:

  • 任务触发:当用户触发特定类型的任务时,FlytePropeller 将通过 gRPC 向相应的 Agent 发送请求。
  • 任务处理:Agent 接收到请求后,会与指定的服务交互(例如 BigQuery、AWS SageMaker 等),并启动对应的任务。
  • 运行环境:每个 Agent 是一个 Kubernetes 部署,运行于 Flyte 的集群中。

2. 核心特点

  • gRPC 通信
    • Flyte Agent 是通过 gRPC 接收来自 FlytePropeller 的任务请求的。
    • 这些任务通常是特定类型(如 BigQuery、Databricks)的工作负载。
  • Kubernetes 部署
    • 每个 Agent 是一个 Kubernetes 部署,运行在集群中,专注于某类任务的管理。
    • Agent 本身无状态,任务的状态由后端服务(如 BigQuery 或 SageMaker)提供。
  • 任务初始化
    • Agent 服务在接收任务后,会与适配的服务进行交互,启动作业或任务。
  • 插件化扩展
    • Flyte 提供了许多预构建的 Agent(如 Airflow Agent、Snowflake Agent)。
    • 用户可以根据需求开发自定义 Agent,用以支持其他任务类型。

3. 常见的 Flyte Agents

以下是一些内置的 Flyte Agents 及其用途:

  • AWS SageMaker Inference Agent:部署模型、创建推理端点并触发推理任务。
  • Airflow Agent:在 Flyte 的工作流中运行 Airflow 作业。
  • BigQuery Agent:在 Flyte 中运行 BigQuery 查询任务。
  • ChatGPT Agent:在工作流中运行 ChatGPT 相关任务。
  • Databricks Agent:在 Flyte 中运行 Databricks 作业。
  • Memory Machine Cloud Agent:使用 MemVerge Memory Machine Cloud 执行任务。
  • OpenAI Batch Agent:提交 OpenAI 异步批处理请求。
  • PERIAN Job Platform Agent:在 PERIAN 平台上执行任务。
  • Sensor Agent:用于工作流中的传感器任务。
  • Snowflake Agent:在 Snowflake 中运行作业。

使用方式

以一个ChatGPT agent为例,ChatGPT 可用于多种场景,例如情感分析、语言翻译、SQL 查询生成以及文本摘要。以下示例展示了如何在 Flyte 中运行 ChatGPT 任务:

1. 安装

pip install flytekitplugins-openai

2. 样例代码

from typing import List
import flytekit
from flytekit import ImageSpec, Secret, dynamic, task, workflow
from flytekitplugins.openai import ChatGPTTask# 需要指定 name、openai_organization 和 chatgpt_config
# name:用于 Flyte,必须唯一。
# openai_organization:OpenAI API 的组织 ID,可以在 [此处](https://platform.openai.com/account/org-settings) 找到。
# chatgpt_config:用于 OpenAI Chat Completion 的配置,可参考 [API 文档](https://platform.openai.com/docs/api-reference/completions)。chatgpt_small_job = ChatGPTTask(name="3.5-turbo",openai_organization="org-NayNG68kGnVXMJ8Ak4PMgQv7",chatgpt_config={"model": "gpt-3.5-turbo","temperature": 0.7,},
)chatgpt_big_job = ChatGPTTask(name="gpt-4",openai_organization="org-NayNG68kGnVXMJ8Ak4PMgQv7",chatgpt_config={"model": "gpt-4","temperature": 0.7,},
)@workflow
def my_chatgpt_job(message: str) -> str:message = chatgpt_small_job(message=message)message = chatgpt_big_job(message=message)return message# 本地运行工作流
if __name__ == "__main__":print(f"Running {__file__} main...")print(f"Running my_chatgpt_job(message='hi') {my_chatgpt_job(message='hi')}")

Agent的部署配置

如果使用的是 Flyte 的托管部署,需要联系部署管理员以在部署中配置代理。比如要在 Flyte 部署中启用 ChatGPT 代理,需要在代理服务器中设置 OpenAI API 密钥才能运行 ChatGPT 任务。详细的方式如下:

1. 指定代理配置

1) 通过Flyte binary

编辑相关的 YAML 文件以指定代理配置:

kubectl edit configmap flyte-sandbox-config -n flyte

在 YAML 文件中添加以下配置:

tasks:task-plugins:enabled-plugins:- container- sidecar- k8s-array- agent-servicedefault-for-task-types:- container: container- container_array: k8s-array- chatgpt: agent-serviceplugins:agent-service:# 配置超时是可选的。# 像使用大模型的 ChatGPT 任务可能需要更长的时间,# 因此可以在这里调整超时设置。defaultAgent:timeouts:ExecuteTaskSync: 10s 

2) 通过Flyte core

创建一个名为values-override.yaml的文件,并向其中添加以下配置:

configmap:enabled_plugins:# -- Tasks specific configuration [structure](https://pkg.go.dev/github.com/flyteorg/flytepropeller/pkg/controller/nodes/task/config#GetConfig)tasks:# -- Plugins configuration, [structure](https://pkg.go.dev/github.com/flyteorg/flytepropeller/pkg/controller/nodes/task/config#TaskPluginConfig)task-plugins:# -- [Enabled Plugins](https://pkg.go.dev/github.com/flyteorg/flyteplugins/go/tasks/config#Config). Enable sagemaker*, athena if you install the backendenabled-plugins:- container- sidecar- k8s-array- agent-servicedefault-for-task-types:container: containersidecar: sidecarcontainer_array: k8s-arraychatgpt: agent-serviceplugins:agent-service:# Configuring the timeout is optional.# Tasks like using ChatGPT with a large model might require a longer time,# so we have the option to adjust the timeout setting here.defaultAgent:timeouts:ExecuteTaskSync: 10s

2. 添加 OpenAI API 密钥

1) 使用 Helm 安装 flyteagent pod:

helm repo add flyteorg https://flyteorg.github.io/flyte
helm install flyteagent flyteorg/flyteagent --namespace flyte

2)将 OpenAI API 密钥设置为秘密(Base64 编码):

SECRET_VALUE=$(echo -n "<OPENAI_API_TOKEN>" | base64) && \
kubectl patch secret flyteagent -n flyte --patch "{\"data\":{\"flyte_openai_api_key\":\"$SECRET_VALUE\"}}"

3)重启开发环境

kubectl rollout restart deployment flyteagent -n flyte 

3. 升级 Flyte 的 Helm 发行版

1)使用 Flyte binary

helm upgrade <RELEASE_NAME> flyteorg/flyte-binary -n <YOUR_NAMESPACE> --values <YOUR_YAML_FILE>

将 <RELEASE_NAME> 替换为您的发行版名称(例如 flyte-backend),<YOUR_NAMESPACE> 替换为您的命名空间名称(例如 flyte),<YOUR_YAML_FILE> 替换为您的 YAML 文件名称。

2)使用Flyte core

helm upgrade <RELEASE_NAME> flyte/flyte-core -n <YOUR_NAMESPACE> --values values-override.yaml 

将 <RELEASE_NAME> 替换为您的发行版名称(例如 flyte),
将 <YOUR_NAMESPACE> 替换为您的命名空间名称(例如 flyte)。

其他集成方式

除了前面三种主要的集成方式,Flyte还有几种集成方式,分布如下:

External service backend plugins

外部服务后端插件,正如其名称所示,这些插件依赖于外部服务来处理使用这些插件定义的 Flyte 任务中的工作负载。

特点:

  • 依赖外部服务:这些插件不是通过 Flyte 自身直接处理任务,而是将任务交由外部服务完成,例如 AWS Athena、AWS Batch、Hive 等。
  • 支持大规模计算任务:借助这些插件,Flyte 可以处理需要大规模资源或专用计算平台的工作负载,例如批量作业、SQL 查询和分布式计算。
  • 灵活性和扩展性:Flyte 的任务定义通过插件扩展了支持范围,使其能够与多种外部服务无缝集成,满足不同工作流的需求。
  • 异步执行能力:外部服务插件通常支持异步工作流,Flyte 会等待外部服务完成任务并返回结果。

原理:

  • 任务提交:Flyte 的任务在定义时通过插件标记为特定类型(例如,Athena 查询、Batch 任务)。
  • 任务调度:Flyte 将任务的执行请求发送到相应的外部服务(如 AWS Batch 或 Hive)。
  • 任务处理:外部服务根据 Flyte 提供的配置处理任务,例如执行 SQL 查询或运行容器化的批处理任务。
  • 结果返回:一旦外部服务完成任务,Flyte 接收返回结果并继续后续的工作流步骤。

这种模式允许 Flyte 保持轻量化,同时利用强大的外部计算服务来满足复杂工作流的需求。

主要类型:

  • AWS Athena:使用 AWS Athena 执行查询。
  • AWS Batch:在 AWS Batch 服务上运行任务和工作流。
  • Flyte Interactive:使用 Flyte Interactive 执行任务以进行调试。
  • Hive:在工作流中运行 Hive 作业。

SDKs for writing tasks and workflows

用于编写任务和工作流的 SDK,社区非常乐意帮助您构建新的 SDK。目前可用的 SDK 包括:

  • flytekit:Flyte 的 Python SDK。
  • flytekit-java:Flyte 的 Java/Scala SDK。

通过这些 SDK,开发者可以更好地利用 Flyte 的功能来构建分布式任务和复杂工作流,同时保持开发过程的高效性和灵活性。

Flyte operators

Flyte 提供Operator,可以与其他编排工具集成,帮助用户在这些工具中原生利用 Flyte 的构建功能。

目前集成了Airflow,从 Airflow 中触发 Flyte 的执行。

相关文章:

Flyte工作流平台调研(五)——扩展集成

系列文章&#xff1a; Flyte工作流平台调研&#xff08;一&#xff09;——整体架构 Flyte工作流平台调研&#xff08;二&#xff09;——核心概念说明 Flyte工作流平台调研&#xff08;三&#xff09;——核心组件原理 Flyte工作流平台调研&#xff08;四&#xff09;——…...

【AUTOSAR 基础软件】软件组件的建立与使用(“代理”SWC)

基础软件往往需要建立一些“代理”SWC来完成一些驱动的抽象工作&#xff08;Complex_Device_Driver_Sw或者Ecu_Abstraction_Sw等&#xff09;&#xff0c;或建立Application Sw Component来补齐基础软件需要提供的功能实现。当面对具体的项目时&#xff0c;基础软件开发人员还可…...

java通过ocr实现识别pdf中的文字

需求&#xff1a;识别pdf文件中的中文 根据github项目mymonstercat 改造,先将pdf文件转为png文件存于临时文件夹&#xff0c;然后通过RapidOcr转为文字,最后删除临时文件夹 1、引入依赖 <dependency><groupId>org.apache.pdfbox</groupId><artifactId&g…...

Git 命令代码管理详解

一、Git 初相识&#xff1a;版本控制的神器 在当今的软件开发领域&#xff0c;版本控制如同基石般重要&#xff0c;而 Git 无疑是其中最耀眼的明珠。它由 Linus Torvalds 在 2005 年创造&#xff0c;最初是为了更好地管理 Linux 内核源代码。随着时间的推移&#xff0c;Git 凭借…...

Docker的安装和使用

容器技术 容器与虚拟机的区别 虚拟机 (VM) VM包含完整的操作系统&#xff0c;并在虚拟化层之上运行多个操作系统实例。 VM需要更多的系统资源&#xff08;CPU、内存、存储&#xff09;来管理这些操作系统实例。 容器 (Container) 容器共享主机操作系统的内核&#xff0c;具…...

Flink系统知识讲解之:Flink内存管理详解

Flink系统知识讲解之&#xff1a;Flink内存管理详解 在现阶段&#xff0c;大部分开源的大数据计算引擎都是用Java或者是基于JVM的编程语言实现的&#xff0c;如Apache Hadoop、Apache Spark、Apache Drill、Apache Flink等。Java语言的好处是不用考虑底层&#xff0c;降低了程…...

使用JMeter模拟多IP发送请求!

你是否曾遇到过这样的场景&#xff1a;使用 JMeter 进行压力测试时&#xff0c;单一 IP 被服务器限流或者屏蔽&#xff1f;这时&#xff0c;如何让 JMeter 模拟多个 IP 发送请求&#xff0c;成功突破测试限制&#xff0c;成为测试工程师必须攻克的难题。今天&#xff0c;我们就…...

【Ubuntu与Linux操作系统:六、软件包管理】

第6章 软件包管理 6.1 Linux软件安装基础 Linux的软件包是以二进制或源码形式发布的程序集合&#xff0c;包含程序文件和元数据。软件包管理器是Linux系统的重要工具&#xff0c;用于安装、更新和卸载软件。 1. 常见的软件包管理器&#xff1a; DEB 系统&#xff08;如Ubunt…...

【数据结构-堆】力扣1834. 单线程 CPU

给你一个二维数组 tasks &#xff0c;用于表示 n​​​​​​ 项从 0 到 n - 1 编号的任务。其中 tasks[i] [enqueueTimei, processingTimei] 意味着第 i​​​​​​​​​​ 项任务将会于 enqueueTimei 时进入任务队列&#xff0c;需要 processingTimei 的时长完成执行。 现…...

【前端动效】原生js实现拖拽排课效果

目录 1. 效果展示 2. 效果分析 2.1 关键点 2.2 实现方法 3. 代码实现 3.1 html部分 3.2 css部分 3.3 js部分 3.4 完整代码 4. 总结 1. 效果展示 如图所示&#xff0c;页面左侧有一个包含不同课程&#xff08;如语文、数学等&#xff09;的列表&#xff0c;页面右侧…...

C#使用OpenTK绘制3D可拖动旋转图形三棱锥

接上篇,绘制着色矩形 C#使用OpenTK绘制一个着色矩形-CSDN博客 上一篇安装OpenTK.GLControl后,这里可以直接拖动控件GLControl 我们会发现GLControl继承于UserControl //// 摘要:// OpenGL-aware WinForms control. The WinForms designer will always call the default//…...

排序的本质、数据类型及算法选择

排序的本质、数据类型及算法选择 一、排序的本质二、排序的数据类型三、排序算法的选择依据 前两天老金写了篇 “十大排序简介”&#xff0c;有点意犹未尽&#xff0c;这一回老金想把排序连根拔起&#xff0c;从排序的本质说道说道。 一、排序的本质 从字面上理解&#xff0c…...

Python的列表基础知识点(超详细流程)

目录 一、环境搭建 二、列表 2.1 详情 2.2 列表定义 2.3 列表长度 2.4 列表索引 2.5 切片索引 2.6 添加 2.7 插入 2.8 剔除 2.8.1 pop方法 2.8.2 del方法 2.9 任何数据类型 2.10 拼接 2.10.1 “” 2.10.2 “*” 2.11 逆序 ​编辑 2.12 计算出现次数 2.13 排序…...

HarmonyOS鸿蒙开发 弹窗及加载中指示器HUD功能实现

HarmonyOS鸿蒙开发 弹窗及加载中指示器HUD功能实现 最近在学习鸿蒙开发过程中&#xff0c;阅读了官方文档&#xff0c;在之前做flutter时候&#xff0c;经常使用overlay&#xff0c;使用OverlayEntry加入到overlayState来做添加悬浮按钮、提示弹窗、加载中指示器、加载失败的t…...

【Ubuntu与Linux操作系统:一、Ubuntu安装与基本使用】

第1章 Ubuntu安装与基本使用 1.1 Linux与Ubuntu Linux是一种开源、类Unix操作系统内核&#xff0c;拥有高稳定性和强大的网络功能。由于其开源性和灵活性&#xff0c;Linux被广泛应用于服务器、嵌入式设备以及桌面环境中。 Ubuntu是基于Debian的一个流行Linux发行版&#xf…...

React 元素渲染

React 元素渲染 React 是一个用于构建用户界面的 JavaScript 库&#xff0c;它允许开发人员创建大型应用程序&#xff0c;这些应用程序可以随着时间的推移而高效地更新和渲染。React 的核心概念之一是元素渲染&#xff0c;它描述了如何将 JavaScript 对象转换为 DOM&#xff0…...

【2024年华为OD机试】 (C卷,100分)- 括号匹配(Java JS PythonC/C++)

一、问题描述 题目描述 给定一个字符串&#xff0c;里边可能包含“()”、“[]”、“{}”三种括号&#xff0c;请编写程序检查该字符串中的括号是否成对出现&#xff0c;且嵌套关系正确。 若括号成对出现且嵌套关系正确&#xff0c;或该字符串中无括号字符&#xff0c;输出&am…...

解锁企业数字化转型新力量:OpenCoze(开源扣子)

在当今数字化浪潮席卷之下&#xff0c;企业对于高效管理和协同运作的需求愈发迫切&#xff0c;而开源技术正逐渐成为众多企业破局的关键利器。今天&#xff0c;想给大家介绍一款极具潜力的开源项目 ——OpenCoze&#xff0c;中文名称 “开源扣子”。 一、OpenCoze 是什么&…...

【网络云SRE运维开发】2025第2周-每日【2025/01/12】小测-【第12章 rip路由协议】理论和实操考试题解析

文章目录 选择题答案及解析理论题答案及解析实操题答案及解析下一步进阶 选择题答案及解析 RIP路由协议是基于哪种算法的动态路由协议&#xff1f; 答案&#xff1a;B. 距离矢量算法解析&#xff1a;链路状态算法用于OSPF等协议&#xff1b;最小生成树算法主要用于生成树协议&…...

【微服务】8、分布式事务 ( XA 和 AT )

文章目录 利用Seata解决分布式事务问题&#xff08;XA模式&#xff09;AT模式1. AT模式原理引入2. AT模式执行流程与XA模式对比3. AT模式性能优势及潜在问题4. AT模式数据一致性解决方案5. AT模式一阶段操作总结6. AT模式二阶段操作分析7. AT模式整体特点8. AT模式与XA模式对比…...

CVE-2025-22777 (CVSS 9.8):WordPress | GiveWP 插件的严重漏洞

漏洞描述 GiveWP 插件中发现了一个严重漏洞&#xff0c;该插件是 WordPress 最广泛使用的在线捐赠和筹款工具之一。该漏洞的编号为 CVE-2025-22777&#xff0c;CVSS 评分为 9.8&#xff0c;表明其严重性。 GiveWP 插件拥有超过 100,000 个活跃安装&#xff0c;为全球无数捐赠平…...

TypeScript Jest 单元测试 搭建

NPM TypeScript 项目搭建 创建目录 mkdir mockprojectcd mockproject初始化NPM项目 npm init -y安装TypeScript npm i -D typescript使用VSCode 打开项目 创建TS配置文件tsconfig.json {"compilerOptions": {"target": "es5","module&…...

基于 SSH 的任务调度系统

文末附有完整项目代码 在当今科技飞速发展的时代&#xff0c;任务调度系统的重要性日益凸显。本文将详细介绍一个基于 SSH&#xff08;SpringStruts2Hibernate&#xff09;的任务调度系统的设计与实现。 一、系统概述 本系统旨在改变传统人工任务调度方式&#xff0c;通过计算…...

filestream安装使用全套+filebeat的模块用法

1 filestream介绍 官方宣布&#xff1a;输入类型为log在filebeat7.16版本已经弃用了 Filestream 是 Filebeat 中的一种 输入类型&#xff08;Input&#xff09;&#xff0c;用于处理日志文件的读取。它是为了取代 Filebeat 中传统的 log 输入&#xff08;Input&#xff09;设…...

java项目之房屋租赁系统源码(springboot+mysql+vue)

项目简介 房屋租赁系统实现了以下功能&#xff1a; 房屋租赁系统的主要使用者分为&#xff1a; 系统管理&#xff1a;个人中心、房屋信息管理、预约看房管理、合同信息管理、房屋报修管理、维修处理管理、房屋评价管理等模块的查看及相应操作&#xff1b; 房屋信息管理&#…...

sap mm学习笔记

1. 业务流程 2. 组织架构 3. 物料主数据 4.采购主数据 5. 采购管理 6. 库存管理 7.物料主数据 8. 采购申请 ME51N...

代码随想录_链表

代码随想录02 链表 203.移除链表元素 力扣题目链接(opens new window) 题意&#xff1a;删除链表中等于给定值 val 的所有节点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[1,2,3,4,5] 示例 2&#xff1a; 输入&#xff1a;he…...

EF Code 并发控制

【悲观控制】 不推荐用&#xff0c;EF Core 没有封装悲观并发控制的使用&#xff0c;需要使用原生Sql来使用悲观并发控制 一般使用行锁、表锁等排他锁对资源进行锁定&#xff0c;同时只有一个使用者操作被锁定的资源 拿sql server举例&#xff0c;可以使用表所、或者行所解决…...

ceph fs status 输出详解

ceph fs status 命令用于显示 Ceph 文件系统的状态信息&#xff0c;其中各列的含义如下&#xff1a; RANK&#xff1a;元数据服务器&#xff08;MDS&#xff09;的等级或标识符。 STATE&#xff1a;MDS 的当前状态&#xff0c;例如 active&#xff08;活跃&#xff09;、stan…...

FFmpeg Muxer HLS

使用FFmpeg命令来研究它对HLS协议的支持程度是最好的方法&#xff1a; ffmpeg -h muxerhls Muxer HLS Muxer hls [Apple HTTP Live Streaming]:Common extensions: m3u8.Default video codec: h264.Default audio codec: aac.Default subtitle codec: webvtt. 这里面告诉我…...

佛山企业快速建站/深圳seo秘籍

声明一个和记录变量s&#xff0c;声明一个阶乘记录变量t&#xff0c;再声明一个计数变量n。用一个for循环&#xff0c;计数变量n从1开始步长为1增值至10为止&#xff1b;t初值设置为1&#xff0c;始终记录它与n的当前值的乘积&#xff0c;就得到了n的当前值的阶乘n!&#xff1b…...

广告安装接单app/推广优化

自己写的分子轨道论文作业……定性分子轨道理论简介文奇实验室一&#xff0e;化学键与分子结构理论的比较化学家们一直都想知道分子内化学键是如何形成&#xff0c;是什么样子的。从路易斯理论开始&#xff0c;理论考虑的越来越多&#xff0c;思考的越来越接近实际&#xff0c;…...

丹东网站网站建设/济南seo培训

你觉得一身才能无处施展吗&#xff1f;你想获得百万奖金吗&#xff1f;快来加入众测申请成为看雪专家吧&#xff01;厂商评级结束即付款&#xff01;测试要求测试范围&#xff1a;Windows程序、智能设备、Android、iOS等二进制程序的漏洞挖掘。项目测试内容及要求&#xff1a;1…...

做网站只有域名/seo推广优化官网

动态修改 行 颜色的方法 rowStyle: function(row, index) { // 参数说明&#xff1a;//row, 行对象&#xff0c;row.xxx, 能获取某个字段的值//index &#xff0c;第几行// 逻辑判断// if (){// }else{// }...return {css:{"background-color":rgba(245,245,245,0.…...

做燕鲍翅的网站/上海做seo的公司

1.如果一个脚本要获取某个物体的引用&#xff0c;在脚本中定义Public GameObject go,在Hierarchy中将对应物体拖过去&#xff0c;这是最常用的方式&#xff0c;很简单 2.如果一个脚本要获取很多物体的引用&#xff0c;当然可以在脚本中定义很多个Public GameObject go变量&…...

做网站学好哪些软件/sem和seo的区别

保护模式&#xff08;二&#xff09;——分段机制&#xff0c;系统门 分段机制 分段机制是历史遗留&#xff0c;实际使用的时候尽量不使用&#xff0c;建议少花时间 BASE:OFFSET表示一个地址。BASE、OFFSET都是16位&#xff0c;若将其当作高位、低位地址&#xff0c;能表示4…...