1 回答
TA贡献1829条经验 获得超4个赞
Go 不执行文件 I/O,它将任务委托给操作系统。请参阅 Go 操作系统依赖syscall
包。
Linux 和 Windows 是具有不同 OS ABI 的不同操作系统。例如,Linux 使用系统调用 viasyscall.Syscall
而 Windows 使用 Windows dll。在 Windows 上,dll 调用是 C 调用。它不使用cgo
. 它不会去通过使用相同的动态的C指针检查cgo
,runtime.cgocall
。没有runtime.wincall
别名。
综上所述,不同的操作系统有不同的操作系统调用机制。
Go 是一种垃圾收集语言,垃圾收集器需要知道每个指向 Go 内存的指针的位置。因此,在 Go 和 C 之间传递指针存在限制。
在本节中,术语 Go 指针表示指向由 Go 分配的内存的指针(例如通过使用 & 运算符或调用预定义的新函数),术语 C 指针表示指向由 C 分配的内存的指针(例如通过调用C.malloc)。一个指针是 Go 指针还是 C 指针是由内存分配方式决定的动态属性;它与指针的类型无关。
如果 Go 代码指向的 Go 内存不包含任何 Go 指针,则 Go 代码可以将 Go 指针传递给 C。C 代码必须保留这个属性:它不能在 Go 内存中存储任何 Go 指针,即使是临时的。当传递指向结构体中字段的指针时,所讨论的 Go 内存是该字段占用的内存,而不是整个结构体。当传递指向数组或切片中元素的指针时,所讨论的 Go 内存是整个数组或切片的整个后备数组。
C 代码可能不会在调用返回后保留 Go 指针的副本。
C 代码调用的 Go 函数可能不会返回 Go 指针。C 代码调用的 Go 函数可能以 C 指针作为参数,它可能通过这些指针存储非指针或 C 指针数据,但它可能不会在 C 指针指向的内存中存储 Go 指针。C 代码调用的 Go 函数可以将 Go 指针作为参数,但它必须保留它所指向的 Go 内存不包含任何 Go 指针的属性。
Go 代码可能不会在 C 内存中存储 Go 指针。C 代码可以将 Go 指针存储在 C 内存中,受上述规则的约束:当 C 函数返回时,它必须停止存储 Go 指针。
这些规则在运行时动态检查。检查由 GODEBUG 环境变量的 cgocheck 设置控制。默认设置是 GODEBUG=cgocheck=1,它实现了相当便宜的动态检查。可以使用 GODEBUG=cgocheck=0 完全禁用这些检查。通过 GODEBUG=cgocheck=2 可以在运行时以一定的代价完成指针处理的检查。
可以通过使用 unsafe 包来破坏这种强制执行,当然没有什么可以阻止 C 代码做任何它喜欢的事情。然而,违反这些规则的程序很可能会以意想不到和不可预测的方式失败。
“这些规则在运行时动态检查。”
基准:
换句话说,有谎言、该死的谎言和基准。
为了跨操作系统进行有效比较,您需要在相同的硬件上运行。例如,CPU、内存和 Rust 或硅磁盘 I/O 之间的差异。我在同一台机器上双引导 Linux 和 Windows。
连续运行基准测试至少 3 次。操作系统试图变得智能。例如,缓存 I/O。使用虚拟机的语言需要预热时间。等等。
知道你在测量什么。如果您正在执行顺序 I/O,您几乎将所有时间都花在操作系统上。您是否关闭了恶意软件保护?等等。
等等。
以下是disk.go
使用双引导 Windows 和 Linux 的同一台机器的一些结果。
视窗:
>go build disk.go
>/TimeMem disk
Duration : 18.3300322s
Elapsed time : 18.38
Kernel time : 13.71 (74.6%)
User time : 4.62 (25.1%)
Linux:
$ go build disk.go
$ time ./disk
Duration : 18.54350723s
real 0m18.547s
user 0m2.336s
sys 0m16.236s
实际上,它们是相同的,disk.go持续时间为18 秒。操作系统之间只是在计算用户时间和计算内核或系统时间方面有所不同。流逝时间或实时时间是相同的。
在您的测试中,内核或系统时间分别为 93.72% runtime.cgocall和 95.49% syscall.Syscall。
- 1 回答
- 0 关注
- 139 浏览
添加回答
举报