news 2026/9/10 4:49:15

Mojo 结构体声明完全指南:字段、方法、参数与 trait 符合性(附仓库源码与测试验证)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Mojo 结构体声明完全指南:字段、方法、参数与 trait 符合性(附仓库源码与测试验证)

Mojo 结构体声明完全指南:字段、方法、参数与 trait 符合性(附仓库源码与测试验证)

【免费下载链接】mojoThe Modular Platform (includes MAX & Mojo)项目地址: https://gitcode.com/GitHub_Trending/mo/mojo

本指南以 Mojo struct declarations 参考文档 及其配套代码示例目录(code/reference/struct-declarations)为核心展开。文章完整覆盖结构体声明的全部语法要素——字段、方法、编译期参数、trait 符合性(含条件符合)、构造/析构生命周期与comptime成员,并结合本仓库编译器源码(MojoParser/MojoParser/StructEmitter.cpp)与可运行测试(tests.mojo)给出底层原理与实战验证。读完本文,你将能够熟练声明参数化、可拷贝、可打印的自定义值类型结构体,并理解 Mojo 编译器如何解析、校验与合成结构体的初始化器。


一、什么是结构体:Mojo 自定义类型的基石

Mojo 中,struct(结构体)定义了一个带字段(fields)和方法(methods)的自定义类型。与许多语言中的"引用类型"不同,Mojo 的结构体是值类型(value type):每个变量持有自己独立的一份副本,而不是指向共享数据的引用。这一点在并发与所有权模型下意义重大——修改一个实例不会影响其他实例,赋值与传参天然是"按值"语义。

参考文档给出的四种声明形态如下(参考文档):

struct Name: body struct Name[parameter-list]: body struct Name(TraitA, TraitB): body struct Nameparameter-list: body

即:结构体名后可以跟方括号编译期参数列表(可选)、圆括号 trait 符合性列表(可选),两者可同时出现。

命名约定:结构体名使用PascalCaseSelf(大写 S)在结构体内部指代结构体自身的类型,self(小写)是实例方法中表示实例的约定俗成参数名。

一个最小但完整的例子(与配套测试test_point_distance完全对应,见 tests.mojo):

from std.math import sqrt struct Point: var x: Int var y: Int def __init__(out self, x: Int, y: Int): self.x = x self.y = y def distance(self) -> Float64: return sqrt( Float64(self.x * self.x + self.y * self.y) ) def main(): var p = Point(3, 4) print(p.distance()) # 5.0

二、结构体体内可以放什么:元素一览

参考文档以表格形式总结了结构体体内允许出现的元素,这是理解结构体能力边界的核心速查表:

元素语法作用
字段(Field)var name: Type实例数据
方法(Method)def name(self, ...)实例行为
静态方法(Static method)@staticmethod def name(...)类型级行为
编译期常量(Compile-time constant)comptime name = value在编译期求值
初始化器(Initializer)def __init__(out self, ...)构造实例
析构器(Deinitializer)def __deinit__(deinit self)生命周期结束时清理

最精简的结构体使用pass作为空体:

struct ValidationError: pass

该例在 tests.mojo 中有对应测试:@fieldwise_init struct ValidationError: pass,并通过ValidationError()直接构造。

限制:结构体不能被嵌套。结构体不能嵌套在另一个结构体、trait 或函数内部:

struct Outer: struct Inner: # Error: nested struct not supported here pass

这一限制在编译器源码中有直接实现依据:Mojo/lib/MojoParser/ParserStmts.cppparseStructStmt()(ParserStmts.cpp)会检查当前父声明是否为StructDeclOpTraitDeclOpFnOp,分别报出 "nested struct not supported here"、"nested struct in a trait not supported here"、"struct inside a function not supported here" 三类错误。源码注释还提示:// We don't support non-top level structs (yet?)——即"顶层之外不支持结构体(目前)",未来可能放开。

三、字段(Fields):声明规则与初始化约束

3.1 每个字段必须用var声明且带类型注解

字段声明以var开头,后跟类型注解。字段不能有默认值,并且所有字段必须在__init__()中完成初始化

struct Color: var r: UInt8 var g: UInt8 var b: UInt8 def __init__(out self, r: UInt8, g: UInt8, b: UInt8): (self.r, self.g, self.b) = (r, g, b)

缺少类型注解会直接报错:

struct Unsound: var x # Error: struct field declaration must have a type

3.2 字段类型必须是具体类型,不能是 trait

字段类型必须是具体类型(concrete),而不能是 trait。想让字段类型"可参数化",应该借助结构体的编译期参数——参数在编译期就固化为具体类型:

struct Unsound: var item: Writable # Error because dynamic traits not supported @fieldwise_init struct Sound[T: Writable & Copyable & Deinitable]: var item: Self.T # OK: concrete at compile time def main(): var g = SoundInt print(g.item) # 42

配套测试test_field_type_parameter(tests.mojo)用assert_equal(g.item, 42)验证了该写法。

3.3@fieldwise_init:按字段合成初始化器

手写__init__()是常规做法,但 Mojo 提供了@fieldwise_init装饰器:编译器按字段列表自动合成一个__init__(),按位置接收每个字段的值:

@fieldwise_init struct Color: var r: UInt8 var g: UInt8 var b: UInt8 def main(): var color = Color(255, 0, 0) print(color.r, color.g, color.b) # 255, 0, 0

测试test_color_fieldwise(tests.mojo)验证了Color_2(255, 0, 0)的三个字段取值。

合成失败的场景:如果某个字段的类型既不可拷贝也不可移动(non-copyable and non-movable),编译器无法合成 fieldwise init:

@fieldwise_init struct Alpha: var a: UInt8 @fieldwise_init struct Color: var r: UInt8 var g: UInt8 var b: UInt8 var alpha: Alpha # Error: cannot synthesize fieldwise init because field # 'alpha' has non-copyable and non-movable type 'Alpha'

源码级原理@fieldwise_init的合成逻辑位于 Mojo/lib/MojoParser/StructEmitter.cpp 的synthesizeFieldwiseInit(),由DeclResolution.cpp第 3897 行调用(见 DeclResolution.cpp)。其实现要点:

  • 遍历结构体的所有字段声明(getFieldDecls()),为每个字段生成一个实参;
  • 对于按值传递的字段,参数约定采用OwnedMem(owned 内存所有权),这保证了对 move-only 字段同样适用;对RegisterPassableTrivial类型则采用ImmReg
  • Self类型本身不是寄存器可传递(memory-only),还会追加一个隐式的out self参数(ByRefResult约定),从而把构造结果"写回"调用方;
  • 合成出的__init__被标记为InlineLevel::AlwaysNoDebug,即总是内联且不产生调试信息。

3.4 递归引用限制

结构体不能引用自身。Mojo 不允许构建一个存储了"另一个自身实例"的类型,即使嵌套在Optional中也不行:

struct Node: var value: String var next: Optional[Node] # Error about this being a recursive # reference

要构建链表、树这类递归数据结构,必须使用不安全指针(unsafe pointers)。这也是 Mojo 所有权模型下类型大小必须静态可知的必然结果——直接或间接自引用会导致类型大小无限递归。

四、编译期参数(Parameters)

结构体用方括号接受编译期参数。参数在结构体体内通过Self访问:Self.T指向参数T裸写T在结构体体内是无效的

@fieldwise_init struct Pair[T: Copyable & Deinitable]: var first: Self.T var second: Self.T

对应测试test_parameterized_pair(tests.mojo)展示了实例化Pair_1Int并断言字段值。

参数同样支持默认值与关键字参数。参考测试中有一个更完整的示例SplatList,展示了带默认值、关键字分隔符*的参数化结构体(tests.mojo):

struct SplatList[ T: ImplicitlyCopyable & Deinitable, *, fill: T, length: Int = 5, ]: var items: List[Self.T] def __init__(out self): self.items = ListSelf.T def test_defaulted_parameters() raises: var l = SplatList[Int, fill=42]() assert_equal(len(l.items), 5) assert_equal(l.items[0], 42) assert_equal(l.items[4], 42)

注意这里length有默认值 5,fill无默认值,因此实例化时只需SplatList[Int, fill=42]()

五、Trait 符合性(Trait Conformance)

在结构体名(或参数列表)后的圆括号中声明 trait 符合性。多个 trait 用逗号分隔,也可以用&组合:

@fieldwise_init struct MyInt(Writable, Copyable): var value: Int def write_toW: Writer: writer.write(self.value) def main(): var my_int = MyInt(42) print(my_int) # 42

符合一个 trait,意味着结构体承诺实现该 trait 要求的所有方法和关联类型。缺失任何一项都会产生编译错误:

@fieldwise_init struct Incomplete(Sized): var value: Int # Error: 'Incomplete' does not implement all requirements # for 'Sized' # Note: required function '__len__' is not implemented

配套测试test_trait_conformance(tests.mojo)用String(my_int)得到"42",验证了Writable符合性让结构体可直接打印。

5.1 符合性列表:trait 与where子句

符合性列表不仅接受 trait,还接受where子句的条件符合

@fieldwise_init struct PairT: Copyable & Deinitable ): var first: Self.T var second: Self.T

conforms_to(T, Equatable)是编译期内置函数,测试T类型是否符合某 trait。这里Pair只有在T本身符合Equatable时才符合Equatable。对应测试test_conformance_where(tests.mojo)验证了Pair_2[Int]的相等性比较行为。

5.2 隐式符合:AnyTypeDeinitable

编译器会自动让每个结构体符合AnyType;当所有成员都可析构(Deinitable)时,还会自动符合Deinitable。对参数化类型而言,参数的 trait 约束中必须包含Deinitable才会生效:

@fieldwise_init struct BoxT: Copyable & Deinitable ): var item: Self.T def main(): var box = Box(42) print(box.item) # OK

反之,如果参数约束缺少Deinitable,编译器无法验证结构体能安全地使用内置__deinit__()析构,从而报错:

@fieldwise_init struct BoxT: Copyable ): var item: Self.T def main(): var box = Box(42) print(box.item) # Error about the 'box' being abandoned without being destroyed.

测试test_box_implicit_destructible(tests.mojo)验证了带DeinitableBox可以正常构造与读取。

5.3 合成的生命周期方法(Synthesized lifecycle methods)

如果结构体符合Movable但未定义__init__(move:),编译器会自动合成一个逐字段移动的初始化器;Copyable__init__(copy:)同理。合成失败的条件是:某字段不支持对应操作。例如符合Copyable但含 move-only 字段:

struct Unsound(Copyable): var item: SomeMoveOnlyType # Error about synthesizing the copy initializer because # field 'item' has non-copyable type SomeMoveOnlyType

5.4 默认方法冲突(Default method conflicts)

当两个 trait 为同一个方法提供了冲突的默认实现时,结构体必须手动实现该方法:

trait A: def foo(self) -> Int: return 42 trait B: def foo(self) -> Int: return 1024 @fieldwise_init struct S(A & B): pass # Error about conflicting default implementations in two traits # reminding you to implement the implementation manually

5.5 条件符合(Conditional conformance)

条件符合让结构体在满足特定条件时才符合某个 trait。参考文档给出五种典型模式——按目标平台、按参数取值、按类型参数性质等:

from std.sys import is_gpu @fieldwise_init struct Mathematical( GPUComputable where is_gpu() ): # conforms only on GPU targets @fieldwise_init struct FixedBufferT: Copyable, N: Int: # conforms if N is one or more, but not if N is zero or negative @fieldwise_init struct Tensordtype: DType ): # conforms when dtype is a floating point type @fieldwise_init struct Taggedkind: StringLiteral: # only conforms in debug mode @fieldwise_init struct BoxT: Copyable ): # conforms to Equatable only when T does

说明:这些示例中的GPUComputableFloatMathPrintable等属于参考文档虚构的(hypothetical)trait 名,用于演示语法形态;配套测试也将其列为跳过项(见 tests.mojo 的 Skip 注释)。

5.6 条件符合与编译期值

条件符合的条件只能依赖编译期可知的信息。它常用 trait 作为约束,但并不局限于 trait——任何能在编译期以清晰一致方式求值的值都可以作为条件,例如"仅在 NVIDIA GPU 或 Apple Silicon(Metal)平台符合某 trait",或"当某个编译期常量为特定值时符合"。

但需要注意:符合性不能依赖于"计算得到的编译期成员"。原因在于 trait 符合性是类型签名的一部分,而签名解析本身需要先解析成员——若符合性依赖某个计算出的成员,就会形成循环依赖(circular dependency)。

5.7 条件符合与默认实现配合使用

条件符合与默认实现是两个独立特性,但经常配合使用。Writabletrait 提供了基于反射自动写出结构体字段的默认实现,前提是所有字段都是Writable

@fieldwise_init struct Point(Writable): var x: Float64 var y: Float64

考虑参数化版本:

@fieldwise_init struct Pair[T: Copyable & Deinitable]: var first: Self.T var second: Self.T

如果T不是Writable,结构体仍可声明Writable符合性,但必须自行实现Writable的必需方法——在没有描述T实例的 API 时,这很不现实。更优雅的方案是条件符合:仅当字段类型可写时Pair才符合Writable,用conforms_to()where子句中测试T

@fieldwise_init struct PairT: Copyable & Deinitable ): var first: Self.T var second: Self.T

这样Pair[Int]可以打印(IntWritable),而Pair[NotWritable]不可以:

@fieldwise_init struct NotWritable(ImplicitlyCopyable & Deinitable): var item: Int def main(): var not_writable = NotWritable(42) var pair = Pair(not_writable, not_writable) print(pair) # Error regarding 'Writable' nonconformance

5.8 混合 trait 列表

同一个符合性列表中可以同时混合条件符合无条件符合的 trait:

@fieldwise_init struct PairT: Copyable & Deinitable, Writable where conforms_to(T, Writable), Copyable ): var first: Self.T var second: Self.T def main(): var pair1 = Pair(first=1, second=2) var pair2 = Pair(first=1, second=2) var pair3 = Pair(first=3, second=4) print(pair1 == pair2) # True print(pair1 == pair3) # False var pair4 = pair1.copy() # OK: Copyable conformance doesn't depend on T _ = pair4

Copyable的符合不依赖T,因此pair1.copy()总是可用;而Equatable/Writable只在T满足条件时生效。测试test_mixed_trait_list(tests.mojo)完整验证了这一行为。

六、方法(Methods)

6.1self参数与可变性约定

实例方法以self作为第一个参数。self的约定(convention)决定访问权限

  • self:不可变引用;
  • mut self:允许修改;
  • outdeinit:用于生命周期方法;
  • out:也可用于指定命名结果槽(named result slot);
  • ref:声明具有参数化可变性的参数,且无论类型如何都必须以内存方式传递。

不带self的实例方法是错误,除非标记@staticmethod

struct Unsound: def broken(): pass # Error: self argument must be present in instance method struct OK: @staticmethod def utility(): # No self required pass

6.2@staticmethod:类型级方法

@staticmethod标记的方法属于类型本身而非实例:

  • 可以访问类型参数和comptime成员;
  • 可以调用其他静态方法;
  • 没有self,无法访问实例字段和实例方法。

静态方法适合与结构体使命相关但无需实例即可工作的工具函数,例如工厂方法(factory methods)和通用辅助函数。

6.3 Dunder 方法

Dunder 方法(双下划线命名,double-underscored)让结构体可以与运算符、内建函数和生命周期事件协同工作:__init__()__add__()__str__()等等。

七、初始化器:实例的诞生

__init__()使用out self约定来"产出"新初始化的值。__init__()返回前,每个字段都必须被赋值

struct Point: var x: Float64 var y: Float64 def __init__(out self, x: Float64, y: Float64): (self.x, self.y) = (x, y) def main(): var p = Point(3.0, 4.0) print(p.x, p.y) # 3.0 4.0

对应测试test_point_float(tests.mojo)断言了字段值。

漏写out self是编译错误

struct Unsound: var value: Int def __init__(self): pass # Error: __init__ method must return Self type with # 'out' argument

此外:__init__()隐式静态的;结构体可以定义多个__init__()重载

八、析构器:实例的终结

__deinit__()在编译器检测到实例不再被访问时运行。其self使用deinit约定:

def __deinit__(deinit self): print("cleaning up")
  • 可隐式析构的结构体(所有成员Deinitable)会获得默认__deinit__()
  • 自定义__deinit__()会覆盖默认实现;
  • __deinit__()不能重载

参考文档补充说明:需要显式销毁的结构体应自行编写清理逻辑(使用带deinit self的消耗性方法);如果想让类型不可析构,可通过Deinitable where False选择退出。

九、comptime成员:编译期常量与类型别名

comptime在结构体体内声明类型级成员,它们在编译期求值、运行期不可修改。适用于常量、类型别名和计算成员:

@fieldwise_init struct Matrix2D[dtype: DType, w: Int, h: Int]: pass struct Test[dtype: DType]: comptime default_size = 1024 comptime DefaultMatrixType = Matrix2D[Self.dtype, Self.default_size, Self.default_size] comptime SquareMatrixType[size: Int] = Matrix2D[Self.dtype, size, size] def main(): print(Test[.int32].default_size) # 1024

这些常量既可以在实例上访问,也可以在类型上访问Test[.int32]().default_sizeTest[.int32].default_size等价。注意定义内部通过Self.dtype引用结构体自身的参数。

配套测试test_comptime_members(tests.mojo)做了更完整的验证:

  • 在类型与实例上分别断言default_size == 1024
  • var _default: CompTest[.int32].DefaultMatrixType = Matrix2D[DType.int32, 1024, 1024]()验证类型别名解析为具体类型;
  • SquareMatrixType[10]验证参数化的 comptime 成员在使用点特化(specialize)。

十、如何构建与运行这些示例:Bazel 工程与测试

这些.mojo示例不是孤立文件,而是被组织成可构建、可测试的 Bazel 目标。BUILD.bazel 给出了通用模式:

load("//bazel:api.bzl", "modular_run_binary_test", "mojo_binary") package(default_visibility = ["//oss/modular/docs:__subpackages__"]) MOJO_SRCS = glob(["*.mojo"]) [ mojo_binary( name = src.split(".")[0], srcs = [src], deps = [ "@mojo//:std", ], ) for src in MOJO_SRCS ] [ modular_run_binary_test( name = src.split(".")[0] + "_test", size = "small", binary = src.split(".")[0], ) for src in MOJO_SRCS ]

该文件用列表推导式为每个.mojo文件同时生成:

  1. 一个mojo_binary目标(目标名 = 文件名去扩展名),依赖@mojo//:std标准库;
  2. 一个modular_run_binary_test测试目标(_test后缀,size = "small"),运行对应二进制。

这两个宏来自 bazel/api.bzl(mojo_binary定义于第 226 行)。测试入口tests.mojomain()依次调用全部 13 个测试函数(tests.mojo),覆盖:Point 距离、最小结构体、手写与 fieldwise 初始化、参数化 Pair、默认参数、trait 符合性、where子句、混合 trait 列表、隐式可析构、Float64 字段与 comptime 成员。

在本仓库中运行测试的命令(基于仓库根目录的./bazelw包装脚本,参见 stdlib 开发文档 的用法约定):

./bazelw test //Mojo/docs/site/code/reference/struct-declarations/...
./bazelw build //Mojo/docs/site/code/reference/struct-declarations/...

其中//Mojo/docs/site/code/reference/struct-declarations:all目标集合由 BUILD.bazel 中的通配生成逻辑覆盖。需要注意的是:测试中所有"构造为失败"的错误示例(嵌套结构体、缺类型字段、动态 trait 字段、递归引用、默认方法冲突等)在 tests.mojo 的头部注释中被明确列为 Skip 项——它们只作为文档中的负例说明错误形态,不参与运行测试。

十一、从源码理解结构体解析与校验流程

参考文档头部注释(见 struct-declarations.mdx)指明了其内容对应的源码实现位置,以下是核心环节的源码证据:

1. 语法解析(Parsing)parseStructStmt(ParserStmts.cpp)负责解析struct关键字、结构体名与参数列表。它要求参数列表与结构体名同行rejectTokenAtStartOfLine),否则会截断声明导致内部错误;解析后通过DeclResolver.addDecl注册声明,延迟到引用时再做类型检查。

2. 签名解析(Signature resolution)resolveSignature(StructDeclOp)resolveSignature(StructFieldOp)(位于 DeclResolution.cpp)解析结构体及其字段的签名;parseOptionalInheritanceList解析圆括号中的继承/符合性列表,verifyDerivedAncestorImplication校验祖先约束蕴含关系。

3. 字段初始化器合成(Fieldwise init synthesis)synthesizeFieldwiseInit(StructEmitter.cpp,声明见 StructEmitter.h)如前文所述,为@fieldwise_init结构体生成__init__,并处理移动/复制初始化器的合成(synthesizeEmptyDtorsynthesizeEmptyMoveOrCopyInitpopulateMoveCopy)。

4. Trait 符合性校验(Conformance checking)verifyAndBuildConformancesignatureResolveDefaultTraitdefStubscheckMethodConstraintStatus(位于 Traits.cpp)负责构建与校验 trait 符合性、解析默认方法存根、检查方法约束状态——这正是"缺失方法报错"(如Incomplete(Sized))与"默认方法冲突报错"的底层来源。

十二、小结

Mojo 结构体是值类型自定义类型的核心语言设施,其能力边界由本文梳理的几条铁律界定:字段必须var+ 类型注解、字段类型必须具体、结构体不可嵌套、不可直接递归自引用(需 unsafe pointers);参数用方括号声明、体内以Self.T访问;trait 符合性声明在圆括号中,支持where条件符合、conforms_to测试与混合列表;生命周期由out self__init__deinit self__deinit__管理;@fieldwise_initcomptime成员则分别简化初始化样板与提供编译期元编程能力。

建议读者将本文与仓库中的三个核心资产对照研读:参考文档(语法规范全文)、tests.mojo(13 个可运行验证用例)、StructEmitter.cpp(初始化器合成实现),即可从"会写"到"懂原理"完整掌握 Mojo 结构体声明。

【免费下载链接】mojoThe Modular Platform (includes MAX & Mojo)项目地址: https://gitcode.com/GitHub_Trending/mo/mojo

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 4:48:33

一站式开发板调试平台BoardLab:串口、引脚、协议一网打尽

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/10 4:47:13

AI工具时代,品味才是拉开差距的核心竞争力

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/10 4:45:54

AI编码省钱实战:WorkBuddy+CNB流水线将API成本降低80%

DeepSeek 这次调价,说白了就是给所有把大模型 API 当“自来水”用的开发者上了一课。尤其是像我这种日常靠 AI 辅助写代码、补注释、跑测试的人,每个月的 API 账单已经从“一杯咖啡”悄悄涨到了“一顿火锅”。涨价本身不是坏事,说明服务真的被…

作者头像 李华
网站建设 2026/9/10 4:45:52

AI视频制作全流程实战:工具选型、提示词与后期包装指南

我从今年上半年开始正经接触AI视频,起因是身边好几个做自媒体和电商的朋友都在问同一件事:那些朋友圈里刷屏的野生动物短片、产品宣传片、个人Vlog配片,到底是不是人拍出来的?是不是要学剪辑、买相机、请模特?实话说&a…

作者头像 李华
网站建设 2026/9/10 4:42:56

CANN/GE ES私有属性构图Python示例

Sample Usage Guide 【免费下载链接】ge GE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、Tensor…

作者头像 李华
网站建设 2026/9/10 4:42:54

CANN/ge私有属性Sigmoid构图示例

Sample Usage Guide 【免费下载链接】ge GE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、Tensor…

作者头像 李华