Gopls:作為守護程序執行
注意:此功能是新推出的。如果您遇到 bug,請提交 issue。
如果您只想嘗試一下,請直接跳轉到快速入門。
背景:gopls 執行模式
Gopls 最初是作為一個 LSP 輔助程序實現的:由編輯器或編輯器外掛啟動,並透過 jsonrpc 2.0 在 stdin/stdout 上進行通訊。透過作為有狀態程序執行,gopls 可以維護大量的快取,並可以主動對正在編輯的原始碼進行分析。
當存在許多獨立的編輯器程序或編輯器程序生命週期很短時,這種執行模式效果不佳,這通常是 Vim 或 Emacs 等非 IDE 編輯器的使用者遇到的情況。擁有許多程序意味著擁有許多快取,佔用了大量的系統資源。使用生命週期短的會話意味著每次建立會話都要支付啟動成本。
為了支援這些工作流,gopls 的執行模式得到了擴充套件,支援一種新的模式:單個、持久的、共享的 gopls “守護程序”負責管理所有 gopls 會話。在此模式下,編輯器仍然會啟動一個 gopls 輔助程序,但該輔助程序僅充當一個輕量級的“轉發器”,負責將 LSP 轉發到共享的 gopls 例項,並記錄指標、日誌和 rpc 跟蹤。
快速入門
要使用共享的 gopls 例項,您必須自己管理守護程序,或者讓 gopls 轉發程序按需啟動共享守護程序。
使用 -remote=auto
執行
守護程序的自動管理是最簡單的,可以透過將標誌 -remote=auto
傳遞給編輯器啟動的 gopls 程序來完成。這將導致該程序在需要時自動啟動 gopls 守護程序,連線到它,並轉發 LSP。例如,下面是一個合理的 gopls 呼叫,它設定了一些額外的標誌以便於除錯。
gopls -remote=auto -logfile=auto -debug=:0 -remote.debug=:0 -rpc.trace
請注意,共享的 gopls 程序在沒有連線客戶端的情況下會在一分鐘後自動關閉。
手動管理守護程序
要透過外部方式管理 gopls 守護程序,而不是讓轉發程序管理它,您必須使用 -listen=<addr>
標誌啟動一個 gopls 守護程序,然後將 -remote=<addr>
傳遞給編輯器啟動的 gopls 程序。
例如,要在 TCP 埠 37374
上託管守護程序,請執行以下操作:
gopls -listen=:37374 -logfile=auto -debug=:0
然後從編輯器中執行:
gopls -remote=:37374 -logfile=auto -debug=:0 -rpc.trace
如果您使用的是 POSIX 系統,也可以透過在標誌值前加上 unix;
來使用 Unix 域套接字。例如:
gopls -listen="unix;/tmp/gopls-daemon-socket" -logfile=auto -debug=:0
並透過以下方式連線:
gopls -remote="unix;/tmp/gopls-daemon-socket" -logfile=auto -debug=:0 -rpc.trace
(請注意,這些標誌值必須用引號括起來,因為 ‘;’ 是一個特殊的 shell 字元。因此,此語法在未來可能會發生變化。)
除錯
除錯共享的 gopls 會話比除錯單例會話更復雜,因為現在有兩個 gopls 程序參與處理 LSP。以下是一些技巧:
查詢日誌檔案和除錯地址
在守護程序模式下執行時,您可以使用 gopls inspect sessions
命令查詢 gopls 守護程序例項(以及所有連線的客戶端)的日誌檔案和除錯埠。預設情況下,這將檢查預設守護程序(即 -remote=auto
)。要檢查不同的守護程序,請明確使用 -remote
標誌:gopls -remote=localhost:12345 inspect sessions
。
無論您是否啟用了 -remote.debug
,此命令都有效。
遍歷除錯頁面
當將 -debug=:0
傳遞給 gopls 時,它會執行一個 Web 伺服器,該伺服器提供有狀態的除錯頁面(請參閱troubleshooting.md)。您可以透過使用 gopls inspect sessions
命令,或者透過檢查日誌檔案的開頭來找到託管這些頁面的實際埠——它將是早期日誌訊息之一。例如,如果使用 -logfile=auto
,請透過檢查 head /tmp/gopls-<pid>.log
來查詢除錯地址。
預設情況下,gopls 守護程序不會以 -debug
啟動。要啟用它,請在轉發器例項上設定 -remote.debug
標誌,以便在啟動守護程序時使用 -debug
呼叫 gopls。
轉發器程序的除錯頁面將有一個連結指向守護程序伺服器程序的除錯頁面。相應地,守護程序程序的除錯頁面將有一個連結指向其每個客戶端。
這可以幫助您找到各種伺服器和客戶端的指標、跟蹤和日誌檔案。
使用日誌檔案
gopls 守護程序預設以停用日誌記錄的方式啟動。要自定義此設定,請向 gopls 轉發器傳遞 -remote.logfile
。使用 -remote.logfile=auto
,守護程序將日誌記錄到預設位置(在 posix 系統上:/tmp/gopls-daemon-<pid>.log
)。
gopls 守護程序不記錄會話範圍的訊息:這些訊息會反射回轉發器,以便編輯器可以訪問。守護程序日誌僅包含全域性訊息,例如會話連線和斷開連線時的日誌。
建議使用 -rpc.trace
啟動轉發器 gopls 程序,這樣它的日誌檔案將包含特定於 LSP 會話的 rpc 跟蹤日誌。
使用多個共享 gopls 例項
在某些環境中,可能希望擁有多個共享的 gopls 例項。如果手動管理守護程序,只需為每個不同的守護程序指定不同的 -listen
地址即可。
在 POSIX 系統上,還支援自動管理不同的共享 gopls 程序:可以透過傳遞 -remote="auto;<id>"
來選擇不同的守護程序。任何傳遞相同 <id>
值的 gopls 轉發器將使用相同的共享守護程序。
常見問題
問:為什麼在使用共享 gopls 時記憶體節省不如預期?
答:如implementation.md中所述,gopls 具有檢視/會話/快取的概念。每個會話和檢視都精確地對映到一個編輯器會話(因為它們包含已編輯但未儲存的緩衝區等內容)。快取包含獨立於任何編輯器會話的內容,因此可以共享。
例如,當三個編輯器會話共享一個 gopls 程序時,它們將共享快取,但每個會話都有自己的會話和檢視。與三個獨立的 gopls 程序相比,此模式下的記憶體節省相當於會話之間快取重疊的量。
由於過去這一點不太重要,因此很可能有一些狀態可以從會話/檢視移到快取中,從而增加共享模式下的記憶體節省量。
問:在使用 -remote=auto
時,如何自定義守護程序例項?
可以使用轉發器 gopls 上的 -remote.*
形式的標誌來自定義守護程序。這會導致轉發器在啟動守護程序時使用這些設定呼叫 gopls。截至目前,我們暴露了以下配置:
-remote.logfile
:守護程序日誌檔案的位置-remote.debug
:守護程序的除錯地址-remote.listen.timeout
:當沒有當前連線時,守護程序在關閉之前等待新連線的時間。必須設定為有效的time.Duration
(例如30s
或5m
)。如果設定為0
,則無限期等待。預設值:1m
。
請注意,一旦守護程序正在執行,設定這些標誌將不會改變其配置。這些標誌僅對實際啟動守護程序的轉發器程序有效。
本文件的原始碼可以在 golang.org/x/tools/gopls/doc 下找到。