Go 部落格
App Engine SDK 和工作區 (GOPATH)
引言
當我們釋出 Go 1 時,我們引入了 go 工具,以及工作區的概念。工作區(由 GOPATH 環境變數指定)是組織程式碼的約定,可以簡化 Go 包的獲取、構建和安裝。如果您不熟悉工作區,請在繼續閱讀之前先閱讀 這篇文章 或觀看 這個螢幕錄影。
直到最近,App Engine SDK 中的工具都無法感知工作區。如果沒有工作區,“go get” 命令無法正常工作,因此應用作者不得不手動安裝和更新其應用依賴項。這很麻煩。
隨著 App Engine SDK 1.7.4 版本的釋出,這一切都改變了。dev_appserver 和 appcfg 工具現在都支援工作區。在本地執行或上傳應用時,這些工具現在會在 GOPATH 環境變數指定的搜尋工作區中查詢依賴項。這意味著您現在可以在構建 App Engine 應用時使用“go get”,並且可以在正常的 Go 程式和 App Engine 應用之間切換,而無需更改您的環境或習慣。
例如,假設您想構建一個使用 OAuth 2.0 對遠端服務進行身份驗證的應用。Go 的一個流行 OAuth 2.0 庫是 oauth2 包,您可以使用以下命令將其安裝到您的工作區:
go get golang.org/x/oauth2
在編寫您的 App Engine 應用時,像在普通 Go 程式中一樣匯入 oauth 包:
import "golang.org/x/oauth2"
現在,無論您是使用 dev_appserver 執行應用還是使用 appcfg 部署應用,這些工具都會在您的工作區中找到 oauth 包。一切都順理成章。
混合獨立/App Engine 應用
Go App Engine SDK 構建在 Go 的標準 net/http 包之上來處理 Web 請求,因此,許多 Go Web 伺服器只需稍作修改即可在 App Engine 上執行。例如,godoc 作為獨立程式包含在 Go 發行版中,但它也可以作為 App Engine 應用執行(godoc 在 App Engine 上提供 golang.org)。
但如果能編寫一個既是獨立 Web 伺服器又是 App Engine 應用的程式,那豈不是很棒?透過使用 構建約束,您可以做到。
構建約束是行註釋,用於確定一個檔案是否應包含在包中。它們最常用於處理各種作業系統或處理器架構的程式碼。例如,path/filepath 包包含 symlink.go 檔案,其中指定了一個構建約束,以確保它不在 Windows 系統上構建(Windows 系統沒有符號連結)。
// +build !windows
App Engine SDK 引入了一個新的構建約束術語:“appengine”。指定
// +build appengine
的檔案將由 App Engine SDK 構建,並被 go 工具忽略。反之,指定
// +build !appengine
的檔案將被 App Engine SDK 忽略,而 go 工具會愉快地構建它們。
goprotobuf 庫使用此機制為其編碼/解碼機制的關鍵部分提供了兩種實現:pointer_unsafe.go 是一個更快的版本,不能在 App Engine 上使用,因為它使用了 unsafe 包;而 pointer_reflect.go 是一個較慢的版本,它透過使用 reflect 包 來避免 unsafe。
讓我們來看一個簡單的 Go Web 伺服器,並將其轉換為一個混合應用。這是 main.go:
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe("localhost:8080", nil)
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello!")
}
使用 go 工具構建此檔案,您將獲得一個獨立的 Web 伺服器可執行檔案。
App Engine 基礎架構提供了自己的 main 函式,該函式執行其等效的 ListenAndServe。要將 main.go 轉換為 App Engine 應用,請刪除對 ListenAndServe 的呼叫,並在 init 函式(在 main 之前執行)中註冊處理程式。這是 app.go:
package main
import (
"fmt"
"net/http"
)
func init() {
http.HandleFunc("/", handler)
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello!")
}
為了使其成為一個混合應用,我們需要將其拆分為特定於 App Engine 的部分、特定於獨立二進位制檔案的部分以及兩者共有的部分。在這種情況下,沒有特定於 App Engine 的部分,因此我們將其拆分為兩個檔案:
app.go 指定並註冊處理程式函式。它與上面的程式碼列表相同,並且不需要構建約束,因為它應該包含在程式的所有版本中。
main.go 執行 Web 伺服器。它包含“!appengine”構建約束,因為它只應在構建獨立二進位制檔案時包含。
// +build !appengine
package main
import "net/http"
func main() {
http.ListenAndServe("localhost:8080", nil)
}
要檢視更復雜的混合應用,請檢視 present 工具。
結論
我們希望這些更改能使處理外部依賴項的應用以及維護包含獨立程式和 App Engine 應用的程式碼庫變得更容易。
下一篇文章:併發不是並行
上一篇文章:兩個最近的 Go 講座
部落格索引