簡體   English   中英

為什么 golang.org/x/sys 包鼓勵使用它要替換的 syscall 包?

[英]Why does the golang.org/x/sys package encourage the use of the syscall package it's meant to replace?

我已經閱讀了一些使用syscall與底層操作系統(例如 Linux 或 Windows)進行低級交互的 Go 代碼。

我想使用相同的包進行本機 Windows 開發,但閱讀其文檔說它已被棄用golang/x/sys

$ go doc syscall
package syscall // import "syscall"

Package syscall contains an interface to the low-level operating system
primitives.

...

Deprecated: this package is locked down. Callers should use the
corresponding package in the golang.org/x/sys repository instead. That is
also where updates required by new systems or versions should be applied.
See https://golang.org/s/go1.4-syscall for more information.

現在,閱讀golang/x/sys的文檔並檢查其代碼,它嚴重依賴並鼓勵使用syscall包:

https://github.com/golang/sys/blob/master/windows/svc/example/beep.go

package main

import (
    "syscall"
)

var (
    beepFunc = syscall.MustLoadDLL("user32.dll").MustFindProc("MessageBeep")
)

func beep() {
    beepFunc.Call(0xffffffff)
}

https://godoc.org/golang.org/x/sys/windows#example-LoadLibrary

...
r, _, _ := syscall.Syscall(uintptr(proc), 0, 0, 0, 0)
...

為什么golang/x/sys依賴並鼓勵使用它要替換的包?

免責聲明:我對 Go 特別陌生(雖然不是低級操作系統編程)。 不過,這里的路徑似乎很清楚。

Go,作為一個生態系統——不僅僅是語言本身,還有所有不同的庫——試圖1是可移植的。 但是直接系統調用幾乎是不可移植的。 所以這里會自動產生一些張力。

為了做任何有用的事情,Go 運行時需要來自操作系統的各種服務,例如創建操作系統級線程、發送和接收信號、打開文件和網絡連接等。 許多這些操作可以並且已經從它在操作系統 A、B 和 C 上的執行方式抽象為大多數或所有操作系統支持的通用概念 這些抽象建立在各種操作系統的實際機制之上。

他們甚至可以在內部分層執行此操作。 例如,查看osGo 源代碼會顯示file.gofile_plan9.gofile_posix.gofile_unix.gofile_windows.go源文件。 file_posix.go的頂部顯示了一個+build指令:

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows

很明顯,這段代碼本身並不是完全可移植的,但它為os實現的例程,由os.File抽象包裝,足以滿足所有符合 POSIX 的系統。 例如,這減少了必須進入 Unix/Linux 特定files_unix.go文件中的代碼量。

如果操作系統級別的操作可以包裝成更抽象、更便攜的操作,那么各種內置的 Go 包就可以做到這一點。 例如,您不需要知道是否有不同的系統調用來打開設備文件、文本文件和二進制文件,或者長路徑名與短路徑名:您只需調用os.Createos.Open ,它會在幕后做任何必要的工作。

這整個想法並不適用於系統調用。 用於創建新 UID 命名空間的 Linux 系統調用沒有 Windows 等效項。 2 Windows WaitForMultipleObjects系統調用在 Linux 上沒有真正的等價物。 stat/lstat 調用的底層細節因系統而異,依此類推。

在 Go 的早期版本中,有人試圖用syscall包來解決這個問題。 但是你引用的鏈接——https : //golang.org/s/go1.4-syscall——將這種嘗試描述為,如果沒有失敗,至少是過度拉伸。 “問題”部分的最后一個詞是“問題”。

同一個鏈接上的提議說,從 Go 1.4 開始, syscall包將被凍結(或大部分被凍結):不要將新功能放入其中。 但是,這它的特點是足以實現新的,實驗golang.org/x/sys/*包,或至少其中的一部分。 借用現有的、正式棄用的syscall包的實驗包沒有壞處,如果它滿足實驗新包的需要。

golang.org/x/是實驗性的:隨意使用它們,但請注意,與標准包中的內容不同,版本更新之間沒有兼容性承諾。 因此,要回答您問題的最后一行:

為什么golang/x/sys依賴 [on] 並鼓勵使用它要替換的包?

依賴於syscall因為這很好。 不過,它根本不“鼓勵使用” syscall 它只是在足夠的時候使用它。 如果這變得不夠,無論出於何種原因,它將停止依賴它。

回答一個你沒有問過的問題(但我問過):假設你想要一個文件的特定於 Unix 的stat信息,比如它的 inode 號。 你有一個選擇:

info, err := os.Stat(path) // or os.Lstat(path), etc
if err != nil { ... handle error ... }
raw, ok := info.Sys().(*syscall.Stat_t)
if !ok { ... do whatever is appropriate ... }
inodeNumber := raw.Ino

或者:

var info unix.Stat
err := unix.Stat(path, &info) // or unix.Lstat, etc
if err != nil { ... handle error ... }
inodeNumber := unix.Ino

第一個代碼塊的優點是您可以獲得有關文件的所有其他(可移植)信息——例如,它的模式、大小和時間戳。 你可能會,也可能沒有得到 inode 編號; !ok案例告訴你你是否做到了。 這里的主要缺點是執行此操作需要更多代碼。

第二個代碼塊的優點是它說明了你的意思。 您要么從stat調用中獲取所有信息,要么不獲取任何信息。 缺點很明顯:

  • 它只適用於 Unix-ish 系統,並且
  • 它使用一個實驗包,其行為可能會改變。

所以這取決於你,其中哪一個對你更重要。


1要么這是一個比喻,要么我只是將其擬人化了。 有一條古老的規則:不要將計算機擬人化,他們討厭那樣!

2 Linux UID 命名空間從容器內的 UID 映射到容器外的 UID。 也就是說,在容器內部,一個文件可能歸 UID 1234 所有。如果該文件位於同樣掛載在容器外部的文件系統中,則該文件可能歸不同的所有者所有,可能是 5678。更改任一所有者的所有權容器的“側”在該側的命名空間中進行更改; 作為通過命名空間映射映射或反向映射 ID 的結果,更改顯示在另一端。

(例如,同樣的技巧也適用於 NFS UID 映射。上面的 Docker 容器示例只是一種用途,但可能是當今最引人注目的一種。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM