- 已编辑
亮点
查看Mojo 手册中的新GPU 基础部分以及使用 Mojo 和 MAX 驱动程序教程开始进行 GPU 编程,获取在 Mojo 中开始进行 GPU 编程的指南!
该包中的某些 API
gpu
已得到增强,以简化 GPU 的使用。
如果您只执行一次 GPU 内核,那么您现在可以跳过将其入队之前的编译步骤,并将其直接传递给
DeviceContext.enqueue_function()
。用于在主机和 GPU 内存之间异步复制缓冲区的三个独立方法
DeviceContext
已合并为单个重载enqueue_copy()
方法,用于同步复制的三个独立方法已合并为一个重载copy_sync()
方法。该
gpu.shuffle
模块已重命名,gpu.warp
以更好地反映其用途。包
gpu
API 文档已经扩展,并且layout
包的 API 文档正在制作中,从核心类型、功能和特征开始。
请参阅变更日志的标准库变更部分以了解更多信息。
旧版
borrowed
/inout
关键字和-> T as foo
语法不再受支持,现在会产生编译器错误。请改用read
/mut
/out
参数语法。有关更多信息,请参阅 Mojo 手册中的参数约定。标准库中有许多与字符串相关的更改。值得注意的是,
Char
类型已重命名为Codepoint
,以更好地体现其存储单个 Unicode 代码点的预期用途。此外,相关方法和类型名称也已更新。有关更多详细信息,请参阅 标准库更改。已添加对 128 位和 256 位有符号和无符号整数的支持。这包括
DType
别名DType.int128
、、DType.uint128
和DType.int256
,DType.uint256
以及SIMD
对 128 位和 256 位有符号和无符号元素类型的支持。请注意,这会暴露 LLVM 的功能(和限制),它可能并不总是为这些类型提供高性能,并且可能缺少除法、余数等运算。有关更多详细信息,请参阅 标准库更改。
语言变化
现在允许引用具有未绑定(或部分)绑定参数集的结构类型中的别名,只要引用的别名不依赖于任何未绑定的参数:
struct StructWithParam[a: Int, b: Int]: alias a1 = 42 alias a2 = a+1 fn test(): _ = StructWithParams.a1 # ok _ = StructWithParams[1].a2 # ok _ = StructWithParams.a2 # error, 'a' is unbound.
struct StructWithParam[a: Int, b: Int]: alias a1 = 42 alias a2 = a+1fn test(): _ = StructWithParams.a1 # ok _ = StructWithParams[1].a2 # ok _ = StructWithParams.a2 # error, 'a' is unbound.
Mojo 编译器现在会警告
@parameter for
循环展开因子过大(默认情况下 >1024),这会导致编译时间过长和生成的代码量过大。设置--loop-unrolling-warn-threshold
为将默认值更改为其他阈值或0
禁用警告。Mojo 编译时解释器现在可以处理更多 LLVM 内部函数,包括返回浮点值的函数。这允许
round()
在编译时上下文中使用函数时进行常量折叠。Mojo 编译器现在只有一个编译时解释器。以前有两个:一个用于处理解析器中对依赖类型很重要的几个情况(但也有很多限制),另一个主要解释器在“实例化”时运行,完全通用。这很令人困惑,并导致了大量错误。我们现在已经删除了特殊情况的解析时解释器,用更通用的依赖类型解决方案取而代之。这一变化对大多数用户来说应该是不可见的,但应该可以解决许多长期存在的错误,并显著简化编译器实现,使我们能够更快地行动。
标准库变更
Optional
、Span
和InlineArray
已添加到 prelude 中。现在您不再需要显式导入这些类型即可在程序中使用它们。GPU 编程变化:
现在,您可以跳过在将其入队之前先编译 GPU 内核的步骤,并将其直接传递给
DeviceContext.enqueue_function()
:
from gpu.host import DeviceContextfn func(): print("Hello from GPU")with DeviceContext() as ctx: ctx.enqueue_function[func](grid_dim=1, block_dim=1)
from gpu.host import DeviceContextfn func(): print("Hello from GPU")with DeviceContext() as ctx: ctx.enqueue_function[func](grid_dim=1, block_dim=1)
但是,如果您多次重复使用相同的函数和参数,则每次入队将产生大约 50-500 纳秒的开销。因此,您仍然可以先编译该函数,
DeviceContext.compile_function()
然后将其传递给它,DeviceContext.enqueue_function()
如下所示:
with DeviceContext() as ctx: var compiled_func = ctx.compile_function[func]() # Multiple kernel launches with the same function/parameters ctx.enqueue_function(compiled_func, grid_dim=1, block_dim=1) ctx.enqueue_function(compiled_func, grid_dim=1, block_dim=1)
with DeviceContext() as ctx: var compiled_func = ctx.compile_function[func]() # Multiple kernel launches with the same function/parameters ctx.enqueue_function(compiled_func, grid_dim=1, block_dim=1) ctx.enqueue_function(compiled_func, grid_dim=1, block_dim=1)
以下方法
DeviceContext
:
enqueue_copy_to_device()
enqueue_copy_from_device()
enqueue_copy_device_to_device()
已合并为一个重载
enqueue_copy()
方法。此外,方法:copy_to_device_sync()
copy_from_device_sync()
copy_device_to_device_sync()
已被合并为一个重载
copy_sync()
方法。
该
gpu.shuffle
模块已重命名,gpu.warp
以更好地反映其用途。例如:
import gpu.warp as warpvar val0 = warp.shuffle_down(x, offset)var val1 = warp.broadcast(x)
import gpu.warp as warpvar val0 = warp.shuffle_down(x, offset)var val1 = warp.broadcast(x)
增加了对 128 位和 256 位有符号和无符号整数的支持。
String
和朋友们:
该
Char
类型已重命名为Codepoint
,以更好地体现其存储单个 Unicode 代码点的预期用途。此外,相关方法和类型名称也已更新,包括:
StringSlice.chars()
和String.chars()
至StringSlice.codepoints()
和String.codepoints()
分别StringSlice.char_slices()
和String.char_slices()
至StringSlice.codepoint_slices()
和String.codepoint_slices()
分别CharsIter
到CodepointsIter
Char.unsafe_decode_utf8_char()
到Codepoint.unsafe_decode_utf8_codepoint()
将字符串
codepoint_slices()
方法返回的迭代器类型公开为CodepointSliceIter
。
StringSlice
现在支持从 移出的几种附加方法String
。现有String
方法已更新为调用相应的新StringSlice
方法:
添加了一种
StringSlice.is_codepoint_boundary()
用于查询给定字节索引是否是编码的 UTF-8 代码点之间的边界的方法。StringSlice.__getitem__(Slice)
如果提供的切片起始和结束位置不在有效的代码点边界上,则现在会引发错误。这可以防止构造格式错误的StringSlice
值,这可能会导致内存不安全或未定义的行为。例如,给定一个包含多字节编码数据的字符串,如:
str_slice = "Hi
!"
str_slice = "Hi
!"
其内存和解码数据如下:
String Hi
!
Codepoint Characters H i!
Codepoints 72 105 128075 33
Bytes 72 105 240 159 145 139 33
Index 0 1 2 3 4 5 6
尝试使用
[3-5)
来切片字节str_slice[3:5]
之前会错误地产生格式错误的StringSlice
输出,该输出无法正确解码为任何内容:
String invalid
Codepoint Characters invalid
Codepoints invalid
Bytes 159 145
Index 0 1
相同的语句现在将引发错误,通知用户他们的索引无效。
StringLiteral.get[value]()
将编译时值转换为类型的方法已Stringable
更改为名为的函数get_string_literal[value]()
。
收藏:
标准库中添加了一个新的
IntervalTree
数据结构。这是一个允许高效范围查询的树形数据结构。添加了迭代器
LinkedList
( PR #4005 )
LinkedList.__iter__()
创建一个前向迭代器。LinkedList.__reversed__()
对于后向迭代器。
var ll = LinkedList[Int](1, 2, 3)for element in ll: print(element[])
var ll = LinkedList[Int](1, 2, 3)for element in ll: print(element[])
List.bytecount()
已重命名为,List.byte_length()
以与类似字符串的 API 保持一致。构造函数
InlineArray(unsafe_uninitialized=True)
现在拼写为InlineArray(uninitialized=True)
。
IntLiteral
和类型的设计FloatLiteral
已更改,以将其编译时值保留为参数而不是存储字段。这正确地模拟了无限精度文字在运行时无法表示的情况,并消除了在极端情况下遇到的许多错误。这是通过编译器中增强的依赖类型支持实现的。该
round()
函数现已修复,执行“四舍五入为偶数”(也称为“银行家舍入”)而不是“四舍五入为远离零的一半”。该
UnsafePointer.alloc()
方法已更改为生成带有空Origin
参数的指针,而不是带有MutableAnyOrigin
。这缓解了任何来源参数延长此通用方法的无关局部变量的生存期的问题。现在有更多的软件包已被记录下来。
添加了新
sys.is_compile_time()
功能。这使您能够查询代码是否在编译时执行。例如:
from sys import is_compile_timefn check_compile_time() -> String: if is_compile_time(): return "compile time" else: return "runtime"def main(): alias var0 = check_compile_time() var var1 = check_compile_time() print("var0 is evaluated at ", var0, " , while var1 is evaluated at ", var1)
from sys import is_compile_timefn check_compile_time() -> String: if is_compile_time(): return "compile time" else: return "runtime"def main(): alias var0 = check_compile_time() var var1 = check_compile_time() print("var0 is evaluated at ", var0, " , while var1 is evaluated at ", var1)
将打印
var0 is evaluated at compile time, while var1 is evaluated at runtime
。
工具变更
Mojo API 文档生成现在能够使用名称而不是索引来显示嵌套参数类型中的函数和结构参数引用。例如,
sort[type: CollectionElement, //, cmp_fn: fn($1|0, $1|0) capturing -> Bool](span: Span[type, origin])
sort[type: CollectionElement, //, cmp_fn: fn($1|0, $1|0) capturing -> Bool](span: Span[type, origin])
现在显示
sort[type: CollectionElement, //, cmp_fn: fn(type, type) capturing -> Bool](span: Span[type, origin])
sort[type: CollectionElement, //, cmp_fn: fn(type, type) capturing -> Bool](span: Span[type, origin])
已移除
使用传统的参数约定(例如
inout
,在命名结果中使用)as
现在会产生错误消息而不是警告。List.size
已删除对 的直接访问。请改用公共 API。
例子:
扩展列表:
base_data = List[Byte](1, 2, 3)data_list = List[Byte](4, 5, 6)ext_data_list = base_data.copy()ext_data_list.extend(data_list) # [1, 2, 3, 4, 5, 6]data_span = Span(List[Byte](4, 5, 6))ext_data_span = base_data.copy()ext_data_span.extend(data_span) # [1, 2, 3, 4, 5, 6]data_vec = SIMD[DType.uint8, 4](4, 5, 6, 7)ext_data_vec_full = base_data.copy()ext_data_vec_full.extend(data_vec) # [1, 2, 3, 4, 5, 6, 7]ext_data_vec_partial = base_data.copy()ext_data_vec_partial.extend(data_vec, count=3) # [1, 2, 3, 4, 5, 6]
base_data = List[Byte](1, 2, 3)data_list = List[Byte](4, 5, 6)ext_data_list = base_data.copy()ext_data_list.extend(data_list) # [1, 2, 3, 4, 5, 6]data_span = Span(List[Byte](4, 5, 6))ext_data_span = base_data.copy()ext_data_span.extend(data_span) # [1, 2, 3, 4, 5, 6]data_vec = SIMD[DType.uint8, 4](4, 5, 6, 7)ext_data_vec_full = base_data.copy()ext_data_vec_full.extend(data_vec) # [1, 2, 3, 4, 5, 6, 7]ext_data_vec_partial = base_data.copy()ext_data_vec_partial.extend(data_vec, count=3) # [1, 2, 3, 4, 5, 6]
有效地切片和扩展列表:
base_data = List[Byte](1, 2, 3, 4, 5, 6)n4_n5 = Span(base_data)[3:5]extra_data = Span(List[Byte](8, 10))end_result = List[Byte](capacity=len(n4_n5) + len(extra_data))end_result.extend(n4_n5)end_result.extend(extra_data) # [4, 5, 8, 10]
base_data = List[Byte](1, 2, 3, 4, 5, 6)n4_n5 = Span(base_data)[3:5]extra_data = Span(List[Byte](8, 10))end_result = List[Byte](capacity=len(n4_n5) + len(extra_data))end_result.extend(n4_n5)end_result.extend(extra_data) # [4, 5, 8, 10]
InlinedFixedVector
和InlineList
已被删除。相反,InlineArray
在编译时已知上限时使用。如果直到运行时才知道上限,则List
与capacity
构造函数一起使用以最小化分配。
已修复
- #3976和
variance
中的参数 已重命名为, 以便从正确的分布中提取值。random.randn_float64()
random.randn()
standard_deviation