MLIR初识 —— Dialect及Operation详解

article/2025/10/13 19:51:38

MLIR初识 —— Dialect及Operation详解

论文链接: MLIR: A Compiler Infrastructure for the End of Moore’s Law

文章目录

  • MLIR初识 —— Dialect及Operation详解
    • 1. MLIR简介
      • 1.1 IR是什么
      • 1.2 常见的IR表示系统
      • 1.3 MLIR的提出
    • 2. Dialect及Operation详解
      • 2.1 Dialect
      • 2.2 Operation
    • 3. 创建新的dialect(添加新的operation)
      • 3.1 定义 Toy Dialect
      • 3.2 加载到 MLIRContext 中
      • 3.3 定义operation
      • 3.4 创建流程总结(使用ODS)
    • 下一篇:Toy接入MLIR

1. MLIR简介

MLIR 全称是 Multi-Level Intermediate Representation (多级中间表示),是一种全新的编译器框架。

1.1 IR是什么

IR即 Intermediate Representation,可以看作是一种数据格式,作为从端到端转换中的中间表示。例如深度学习模型一般表示为计算图,能够表示计算图的数据结果就可以称为一种IR,例如ONNXTorchScriptTVM Relay等等。

  • ONNX(Open Neural Network Exchange) : ONNX 协议首先由微软和Meta提出,它定义了一组和环境、平台均无关的标准格式(如算子功能)。在训练完成后可以将支持框架(Pytorch、Tensorflow等)的模型转化为 ONNX 文件进行存储,ONNX 文件不仅存储了神经网络模型的权重,也存储了模型的结构信息以及网络中每一层的输入输出等信息。
  • TorchScrpit : PyTorch 最大的卖点是它对动态网络的支持,比其他需要构建静态网络的框架拥有更低的学习成本。但动态图模式在每次执行计算时都要重新构造计算图,非固定的网络结构给网络结构分析并进行优化带来了困难。TorchScript 就是为了解决这个问题而诞生的工具,包括代码的追踪及解析、中间表示的生成、模型优化、序列化等各种功能。
  • Relay IR : 与 TVM 框架绑定,是一个函数式、可微的、静态的、针对机器学习的领域定制编程语言,解决了普通DL框架不支持 control flow 以及 dynamic shape 的特点,使用 lambda calculus 作为基准IR。

1.2 常见的IR表示系统

在这里插入图片描述

在上图表示中:

(1) 由于 C、C++ 源码直接转成 AST 时,并不会进行语言特定的优化,程序的优化主要集中于 LLVM IR 阶段。但 LLVM IR 表示层级较低,会丢失源码中的部分信息(如报错信息),会导致优化不充分

(2) 类似于Tensorflow、Keras等框架,会先转化为计算图Computation Graph形式,然后会基于图做一定的优化。但图阶段缺少硬件部署的相关信息,所以后续会转化为某个后端的内部表示,根据不同的硬件(TPU、Phone),进行算子融合等等优化。

可见,当前IR表示系统主要的问题

  • 可复用性差:针对不同种类IR开发的Pass(优化)可能重复,但不同IR的同类Pass可能并不兼容。
  • 不透明:前层IR所作的Pass优化在后层中不可见,可能导致优化重复。
  • 变换开销大:转换过程中存在多种IR,这些不同类型的IR转换时开销很大。

1.3 MLIR的提出

Tensorflow 团队较早时采用了多种IR的部署,这样导致软件碎片化较为严重。

因此 Tensorflow 团队就提出了 MLIR,主要是为了统一各类IR格式,协调各类IR的转换,带来更高的优化效率

在这里插入图片描述

2. Dialect及Operation详解

参考:

Chapter 2: Emitting Basic MLIR - MLIR (llvm.org)

MLIR Toy Tutorials 第二章 生成初步的 MLIR 代码 - 知乎 (zhihu.com)

MLIR & python binding简介_哔哩哔哩

2.1 Dialect

  1. Dialect 是什么?

从源程序到目标程序,要经过一系列的抽象以及分析,通过 Lowering Pass 来实现从一个IR到另一个IR的转换。但IR之间的转换需要统一格式,统一IR的第一步就是要统一“语言”,各个IR原来配合不默契,谁也理解不了谁,就是因为“语言”不通。

因此 MLIR 提出了Dialect,各种IR可以转换为对应的 mlir Dialect,不仅方便了转换,而且还能随意扩展。不妨将dialect看成各种具有IR表达能力的黑盒子,之后的编译流程就是在各种dialect之间转化。

在这里插入图片描述

  1. dialect 是怎么工作的?

dialect 将所有的IR放在了同一个命名空间中,分别对每个IR定义对应的产生式并绑定相应的操作,从而生成一个MLIR的模型。

每种语言的 dialect(如tensorflow dialect、HLO dialect、LLVM IR dialect)都是继承自 mlir::Dialect,并注册了属性、操作和数据类型,也可以使用虚函数来改变一些通用性行为。

整个的编译过程:从源语言生成 AST(Abstract Syntax Tree,抽象语法树),借助 dialect 遍历 AST,产生 MLIR 表达式(此处可为多层IR通过 Lowering Pass 依次进行分析),最后经过 MLIR 分析器,生成目标硬件程序。

在这里插入图片描述

  1. dialect 内部构成

dialect主要是由自定义的 TypeAttributeInterface 以及 operation 构成。operation 细分为Attribute、Type、Constraint、Interface、Trait(属性、类型、限制、接口、特征)。同时存在 ODS 和 DRR 两个重要的模块,这两个模块都是基于 tableGen 模块,ODS 模块用于定义 operation ,DRR 模块用于实现两个 dialect 之间的 conversion

在这里插入图片描述

2.2 Operation

Operation 是 Dialect 的重要组成部分,是抽象和计算的核心单元,可以看成是方言语义的基本元素。

下面的例子可理解为:

生成的结果是 %t_tensor,toy dialect,执行的是 transpose 操作,输入数据是 %tensor,能够将 tensor<2x3xf64> 的数据转换成tensor<3x2xf64> 的数据,该 transpose 的位置在 “example/file/path”,第12行,第1个字符

%t_tensor = "toy.transpose"(%tensor) {inplace = true} : (tensor<2x3xf64>) -> tensor<3x2xf64> loc("example/file/path":12:1)

结构拆分解析:

(1)%t_tensor:定义结果名称,SSA值,由%<t_tensor>构成,一般<t_tensor>是一个整数型数字。

IR 是 LLVM 的设计核心,它采用 SSA(Single-Static Assignments,静态单赋值)的形式,并具备两个重要特性:

  • 代码被组织成三地址指令
  • 有无限的寄存器

(2)"toy.transpose":操作的名称,应该是唯一的字符串,方言空间以.开头;指明为 Toy Dialect 的transpose 操作;.之前的内容是 Dialect 命名空间的名字,.后面是操作的名称。

(3)(%tensor):输入的操作数的列表,多个操作数之间用逗号隔开。

(4){inplace = true}:属性字典,定义一个名为inplace的布尔类型,其常量值为true

(5)(tensor<2x3xf64>) -> tensor<3x2xf64>:函数形式表示的操作类型,前者是输入,后者是输出。<2x3xf64>号中间的内容描述了张量的尺寸2x3和张量中存储的数据类型f64,中间使用x连接。

(6)loc("example/file/path":12:1):此操作的源代码中的位置。每个操作都有与之关联的强制性源位置,在 MLIR 中是核心要求,并且 API 依赖并操纵他。例如:如果一个转换将操作替换成另一个操作,必须在新的操作中附加一个位置,可以追踪该操作的来源。所以,在使用工具链 mlir-opt 中默认没有这个位置信息,添加 -mlir-print-debuginfo 标志指定要包含位置。

更一般的格式可见下图:

在这里插入图片描述

3. 创建新的dialect(添加新的operation)

本节创建新的dialect包括 手动编写C++创建 以及 利用ODS框架生成

ODS 全称 Operation Definition Specification,操作者只需要根据 operation 框架定义的规范,在一个.td文件中填写相应的内容,使用 mlir 的 tableGen 工具就可以自动生成上面的 C++ 代码。

本节完全参考官方文档 :Chapter 2: Emitting Basic MLIR - MLIR (llvm.org)

本节将以Toy语言为例,演示构造 Toy Dialect并添加相应的Operation的流程。

Toy语言是为了验证及演示MLIR系统的整个流程而开发的一种基于Tensor的语言。
Toy 语言具有以下特性:

  • Mix of scalar and array computations, as well as I/O
  • Array shape Inference
  • Generic functions
  • Very limiter set of operators and features

3.1 定义 Toy Dialect

Dialect 将对 Toy 语言的结构进行建模,并为高级分析和转换提供方便的途径。

1. 使用 C++ 语言手动编写

// 下面是官方给出的Toy Dialect定义
// 默认位置为 ../mlir/examples/toy/Ch2/include/toy/Dialect.h
class ToyDialect : public mlir::Dialect {
public:explicit ToyDialect(mlir::MLIRContext *ctx);/// Provide a utility accessor to the dialect namespace.static llvm::StringRef getDialectNamespace() { return "toy"; }/// An initializer called from the constructor of ToyDialect that is used to/// register attributes, operations, types, and more within the Toy dialect.void initialize();
};

2. 使用 ODS 框架自动生成

在使用 ODS 定义操作的这些代码,都在Ops.td中,默认位置为 …/mlir/examples/toy/Ch2/include/toy/Ops.td

下面的代码块定义一个名字为 Toy 的 Dialect 在 ODS 框架中,使用let <...> = "..."/[{...}];方式依次明确 name、summary、description 和 cppNamespace(对应 Dialect 类所在的 C++ 命名空间)各个字段的定义。

def Toy_Dialect : Dialect {// The namespace of our dialect, this corresponds 1-1 with the string we// provided in `ToyDialect::getDialectNamespace`.let name = "toy";// A short one-line summary of our dialect.let summary = "A high-level dialect for analyzing and optimizing the ""Toy language";// A much longer description of our dialect.let description = [{The Toy language is a tensor-based language that allows you to definefunctions, perform some math computation, and print results. This dialectprovides a representation of the language that is amenable to analysis andoptimization.}];// The C++ namespace that the dialect class definition resides in.let cppNamespace = "toy";
}

然后在编译阶段,由框架自动生成相应的 C++ 代码。当然也可以运行下面的命令 直接得到生成的 C++ 代码。

${build_root}/bin/mlir-tblgen -gen-dialect-decls ${mlir_src_root}/examples/toy/Ch2/include/toy/Ops.td -I ${mlir_src_root}/include/

下图中右侧是 ODS 中的定义,左侧是自动生成的 C++ 代码。

在这里插入图片描述

3.2 加载到 MLIRContext 中

定义好 Dialect 之后,需要将其加载到 MLIRContext 中。默认情况下,MLIRContext 只加载内置的 Dialect,若要添加自定义的 Dialect,需要加载到 MLIRContext。

// 此处的代码与官方文档中的稍有不同,但实际意义相同。
// 在代码文件 toyc.cpp 中,默认位置为 ../mlir/examples/toy/Ch2/toyc.cpp。
int dumpMLIR() {
...// Load our Dialect in this MLIR Context.context.getOrLoadDialect<mlir::toy::ToyDialect>();
...
}

3.3 定义operation

有了上述的 Toy Dialect,便可以定义操作(operation)。官方文档围绕 Toy toy.ConstantOp 的定义介绍如何使用 C++ 的方式直接定义 operation。

# 此操作没有输入,返回一个常量。
%4 = "toy.constant"() {value = dense<1.0> : tensor<2x3xf64>} : () -> tensor<2x3xf64>

1. 使用 C++ 语言手动编写

operation 类是继承于 [CRTP](Curiously recurring template pattern - Wikipedia) 类,有一些可选的 traits 来定义行为。下面是 ConstantOp 的官方定义:

// `mlir::Op` is a CRTP class
class ConstantOp : public mlir::Op<ConstantOp, // The ConstantOp mlir::OpTrait::ZeroOperands, // takes zero input operandsmlir::OpTrait::OneResult, // returns a single result.mlir::OpTraits::OneTypedResult<TensorType>::Impl> {public:// Op inherit the constructors from the base Op class.using Op::Op; // Return a unique name of the operationstatic llvm::StringRef getOperationName() { return "toy.constant"; }// Return a value by fetching it from the attributemlir::DenseElementsAttr getValue(); // Operations may provide additional verification beyond what the attached traits provide.LogicalResult verifyInvariants(); // Provide an interface to build this operation from a set of input values.// mlir::OpBuilder::create<ConstantOp>(...)// Build a constant with the given return type and `value` attribute.static void build(mlir::OpBuilder &builder, mlir::OperationState &state,mlir::Type result, mlir::DenseElementsAttr value);// Build a constant and reuse the type from the given 'value'.static void build(mlir::OpBuilder &builder, mlir::OperationState &state,mlir::DenseElementsAttr value);// Build a constant by broadcasting the given 'value'.static void build(mlir::OpBuilder &builder, mlir::OperationState &state,double value);
};

定义好 operation 的行为后,我们可以在 Toy Dialect 的 initialize 函数中注册(register),之后才可以正常在 Toy Dialect 中使用 ConstantOp。

// 位于../mlir/examples/toy/Ch2/mlir/Dialect.cpp
void ToyDialect::initialize() {addOperations<ConstantOp>();
}

2. 使用 ODS 框架自动生成

首先在 ODS 中定义一个继承自 Op 类的基类 Toy_Op

Operation 和 Op的区别

Operation:用于对所有操作的建模,并提供通用接口给操作的实例。

Op:每种特定的操作都是由 Op 类继承来的。同时它还是 Operation * 的 wrapper,这就意味着,当我们定义一个 Dialect 的 Operation 的时候,我们实际上是在提供一个 Operation 类的接口。

Op 类的定义在 OpBased.td 文件中,默认位置为 …/mlir/include/mlir/IR/OpBased.td。

下面的代码都在Ops.td中,默认位置为 …/mlir/examples/toy/Ch2/include/toy/Ops.td

class Toy_Op<string mnemonic, list<OpTrait> traits = []> :Op<Toy_Dialect, mnemonic, traits>;
// Toy_Dialect : 父类 Dialect 操作
// mnemonic : 注记符号,一般是一个字符串型的单词,代表了该操作的含义
// traits : 该操作的一些特征,放在一个列表中

其次以声明的方式定义相应操作:

def ConstantOp : Toy_Op<"constant", [NoSideEffect]> {// "constant"就是注记符号,[NoSideEffect]说明了该操作的一个特点// Provide a summary and description for this operation. let summary = "constant";let description = [{Constant operation turns a literal into an SSA value. The data is attachedto the operation as an attribute. For example:```mlir%0 = toy.constant dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]>: tensor<2x3xf64>```}];/*arguments和results:定义参数和结果,参数可以是SSA操作数的属性或类型。通过为参数或结果提供名称,ODS将自动的生成匹配的访问器。arguments一般模板(results同理): let arguments = (ins <data_type><data_attribute>:$<variable_name>);- ins: 输入 (results中该参数为 outs)- <data_type>: 数据类型- <data_structure>: 数据属性- ElementsAttr: 稠元(dense element)- <variable_name>: 变量名*/// The constant operation takes an attribute as the only input.// `F64ElementsAttr` corresponds to a 64-bit floating-point ElementsAttr.let arguments = (ins F64ElementsAttr:$value);// The constant operation returns a single value of TensorType.let results = (outs F64Tensor);// Divert the printer and parser to `parse` and `print` methods on our operation.let hasCustomAssemblyFormat = 1;/*// 自定义程序的组装格式,使最终输出的 IR 格式更精简、易读let parser = [{ return ::parseConstantOp(parser, result); }];let printer = [{ return ::print(p, *this); }];*/// ODS 可以自动生成一些简单的构建方法,用户也可自定义添加一些构造方法let builders = [// Build a constant with a given constant tensor value.OpBuilderDAG<(ins "DenseElementsAttr":$value), [{build($_builder, $_state, value.getType(), value);}]>,// Build a constant with a given constant floating-point value.OpBuilderDAG<(ins "double":$value)>];// Add additional verification logic to the constant operation.// will generate a `::mlir::LogicalResult verify()`let hasVerifier = 1;
}

然后在编译阶段,由框架自动生成相应的 C++ 代码。当然也可以运行下面的命令 直接得到生成的 C++ 代码。

${build_root}/bin/mlir-tblgen -gen-op-defs ${mlir_src_root}/examples/toy/Ch2/include/toy/Ops.td -I ${mlir_src_root}/include/

下图中右侧是 ODS 中的定义,左侧是自动生成的 C++ 代码。

在这里插入图片描述

官方的文档在这时候没提及需要在 Toy Dialect 的 initialize 函数中注册生成的Op

3.4 创建流程总结(使用ODS)

整个 tableGen 模块是基于 ODS (Operation Definition Specification)框架进行编写以及发挥作用。tableGen 模块促进了自动化生成,减少了 operation 的手动开发,并且避免了冗余开发。

我们以添加 Toy Dialect为例,总结添加流程如下:

Ops.td文件默认位置为 …/mlir/examples/toy/Ch2/include/toy/Ops.td

① (在Ops.td中) 定义一个和 Toy Dialect 的链接

def Toy_Dialect : Dialect {let name = "toy";...let cppNamespace = "toy";
}

② (在Ops.td中) 创建 Toy Dialect Operation 基类

class Toy_Op<string mnemonic, list<OpTrait> traits = []> :Op<Toy_Dialect, mnemonic, traits>;

③ (在Ops.td中) 创建 Toy Dialect 中各种 Operation

def ConstantOp : Toy_Op<"constant", [NoSideEffect]> {let summary = "constant";let arguments = (ins F64ElementsAttr:$value);let results = (outs F64Tensor);let builders = [OpBulider<"Builder *b, OperationState &state, Value input">];let verifier = [{ return ::verify(*this); }];
}

④ 通过 mlir-tblgen 工具生成 C++ 文件

使用 mlir-tblgen -gen-dialect-decls 命令生成对应的 Dialect.h.inc 文件。

使用 mlir-tblgen -gen-op-defs 命令生成对应的 Ops.h.inc 文件。

在这里插入图片描述

使用 #include 直接引用生成文件

#include "toy/Dialect.h.inc"
#include "toy/Ops.h.inc"

下一篇:Toy接入MLIR

MLIR深入 —— 转换流程详解(以Toy接入为例)


http://chatgpt.dhexx.cn/article/K8pxJPtq.shtml

相关文章

java里dialect_iBatis3基于方言(Dialect)的分页

(注:以下代码是基于ibatis3 beta4的扩展&#xff0c;ibatis3正式版如果实现改变&#xff0c;将会继续跟进修改) iBatis3默认使用的分页是基于游标的分页&#xff0c;而这种分页在不同的数据库上性能差异不一致&#xff0c;最好的办法当然是使用类似hibernate的基于方言(Dialect…

mysql的dialect_hibernate的dialect大全

配第二个beanfactory方法: 1.下载最新版本的mssql最新驱动,把这个驱动复制到tomcat的lib下面!!这一步非常重要,耗费我两天查原因。不拷你就等着报没找到资源吧! 2.驱动加入web项目 3.添加配置文件 注意驱动类名的写法,< msql2005之前,是这么写的:(真的,这个太CNM了…

dialect和Cantonese:土话与方言

一、 dialect&#xff1a;方言 1.土话 土话是指在某一区域的当地人使用的方言&#xff0c; 如广东话、上海话等&#xff0c;其发音与普通话差别很大。土语一般只在同类人群中使用&#xff0c;而在公共场合常用普通话交流。 2.地方话 地方话指的是一个国家或地区所使用的语言…

Dialect及Operation详解

参考资料&#xff1a; [MLIR] Dialect及Operation详解 - 知乎 (zhihu.com) 2. Dialect 及Operation 2.1Dialect 2.1.1Dialect 是什么&#xff1f; 从源程序到目标程序&#xff0c;要经过一系列的抽象以及分析&#xff0c;通过 Lowering Pass 来实现从一个IR到另一个IR的转换。…

神州战神笔记本开启/关闭键盘背光灯的方法,control center使用配置,控制风扇转速,减少噪音

control center控制噪音是有效的。windows更新后&#xff0c;需要重新打开control center。 1、control center路径&#xff1a; c:\Program Files\Hotkey或c:\Program Files(x86)\Hotkey目录下。 2、进入配置界面&#xff1a; 3、调整风扇转速&#xff0c;控制噪音&#xff…

笔记本电脑键盘颜色不切换及control center打不开问题解决方法

文章目录 问题描述解决方法对于键盘颜色不切换control center打不开 问题描述 我的雷神笔记本电脑&#xff0c;出现开机时&#xff0c;键盘颜色不切换&#xff0c;重新安装驱动后control center打不开&#xff0c;虽然感觉这个键盘颜色不太影响我的使用&#xff0c;但是就是不…

打印机添加或者设置流程

作者&#xff1a;蓝眼泪 这里以震旦打印机的添加作为参考 环境准备&#xff1a;xp&#xff0c;win7或者win10操作系统&#xff0c;震旦打印机驱动。 1 开始 运行 输入命令 control 2 选择类别&#xff0c;打印机 3 添加打印机-我需要的打印机未列出&#xff0c;tcp/it,下一步…

linux运行mate,在Ubuntu MATE系统上自动启动程序的方法

Mate桌面环境有很多设置,用户可以利用这些设置进行自定义,本文要讲的是自动启动功能,因为它允许用户自动启动Ubuntu MATE上的程序,可以决定Ubuntu MATE系统如何加载程序,脚本甚至服务。在Mate桌面上配置自动启动功能是通过系统设置完成的。如果需要启用系统自动登陆,请参…

访问 的请求遭到拒绝_服务器端请求伪造(SSRF)攻击导致大量科技、工业和媒体组织信息泄露...

摘要 服务器端请求伪造(SSRF)是一个Web应用程序漏洞&#xff0c;可将攻击者的请求重定向到防火墙后的内部网络或本地主机。由于使用了元数据API&#xff0c;因此SSRF对云服务构成了特殊的威胁&#xff0c;这些元数据API允许应用程序访问底层云基础架构的信息&#xff0c;例如配…

【控制中心】让你的 Mac 系统更方便

macOS 11 中新加入的功能 - 【控制中心】。 虽然说是 Mac 新加入的功能&#xff0c;不过使用 iPhone 和 iPad 的朋友其实早就用到这个功能了。 【控制中心】是将之前散落在系统各处的控制功能集中在一处&#xff0c;方便用户使用&#xff0c;这个功能显然非常重要&#xff0c…

windows下运行 jar包后台运行以及杀死后台进程

比如要运行该jar包 输入命令 java -jar demo-0.0.1-SNAPSHOT.jar 如果端口被占用&#xff1f;&#xff1f;&#xff1f;&#xff1f;这个初学者经常碰到 cmd 查找指定端口比如8080 netstat -aon | findstr "8080" 杀死pid为23604的进程 tasklist|findstr "23…

ssh远程登录遇到的一系列问题

1.报的啥错我不记得了&#xff0c;有一个refuse 确认一下win10的ssh客户端和服务器都安装、启动了没。 2.用Xshell登录显示&#xff1a;SSH服务器拒绝了密码&#xff0c;请再试一次 这个问题我搜了很多方法&#xff0c;基本数都是让改配置文件。 我在确认物理机和虚拟机互相…

【Windows使用笔记】神舟笔记本的control center

首先&#xff0c;神船大法好。 然后&#xff0c;因为我的船风扇声音有点大啊&#xff0c;在实验室感觉就很吵&#xff0c;但是它的背板温度又不是很高&#xff0c;所以想设置下风扇的启动。 所以需要用到神船自带的control center软件。 长这样。 应该使用热键fnesc就可以调用出…

MIL开发实践(4)——E2v相机参数

目录 前言效果图正文连接串口向串口写入命令举例设置的参数ComBox类型Int类型 总结 前言 这篇文章的主要内容是完成对相机参数这部分的配置。因为这个相机参数这个接口的特殊原因&#xff0c;只能采用串口的形式才能对相机的参数进行设置&#xff0c;所以&#xff0c;需要具备…

机械师怎么打开计算机管理,机械师创物者-R笔记本智能控制中心使用教程

②在官网“驱动下载”页面下选择“MACHENIKE-R”对应的配置驱动,找到“控制中心驱动”选项,点击“立即下载”。 ③ 下载完成后,对zip压缩包进行解压操作,双击文件夹中的“UniwillService.exe”开始安装。 ④ 软件的安装流程十分简单,只需要点击进程中的“install”选项开始…

[基础]tfcenter的安装和启动

文章系列 tfcenter的安装和启动 tfcenter开启端口映射功能 tfcenter开启本地文件功能 tfcenter开启Webdav文件服务 tfcenter开启http代理功能 tfcenter开启socks5代理功能 tfcenter搭建个人服务器 tfcenter支持端口映射、本地文件管理、Webdav文件服务、http代理和socks…

redis简单介绍

&#xff08;一&#xff09;redis简介 what: Redis是一个开源的、基于内存的缓存数据库 Redis&#xff1a;支持每秒十几万此的读/写操作 场景&#xff1a;由于一般的系统任务中通常不会存在高并发的情况&#xff0c;所以这样看起来并没有什么问题&#xff0c;可是一旦涉及大…

Mac端口5000被ControlCe占用问题解决方法

问题 Mac上运行flask应用时提示端口5000已被占用。 查看占用情况&#xff1a; $ lsof -i:5000 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME ControlCe 70052 jiaqi 24u IPv4 0xa620acf2cebbe09f 0t0 TCP *:commplex-main (LISTEN) C…

android 控制中心os,控制中心Control Center--IOS 11

控制中心Control Center--IOS 11 介绍 控制中心Control Center--IOS 11 ?控制中心Control Center--IOS 11便捷操控手机&#xff0c;一键访问相机&#xff0c;闹钟等功能和应用&#xff0c;便捷调控音量等 控制中心Control Center--IOS 11完美适配三星&#xff0c;华为&#xf…

触摸板失效,fn快捷键不显示,神舟control center3.0无法打开等问题重装驱动

神舟电脑 Hasee -- 服务与支持 在上面的网站找到自己电脑型号的驱动&#xff0c;然后找到控制中心或者热键的驱动&#xff0c;我的是控制中心 下载解压好之后进行安装 安装好之后找到这个路径&#xff0c;我是把里面的东西都安装了一遍&#xff0c;安装好后他自动打开是英文的…