2 回答

TA貢獻1816條經驗 獲得超6個贊
有沒有更慣用的方法來進行這種計算?
您實際上不需要循環來計算它。
如果你使用GCD 函數(標準庫的一部分),你會得到返回的數字 x 和 y,這樣:
x*P+y*Base=1
這意味著 x 是您想要的答案(因為 x*P = 1 modulo Base):
package main
import (
? ? "fmt"
? ? "math/big"
)
const (
? ? P? ? = 1000099
? ? Base = 1<<31 - 1
)
func main() {
? ? bigP := big.NewInt(P)
? ? bigBase := big.NewInt(Base)
? ? // Compute inverse of bigP modulo bigBase
? ? bigGcd := big.NewInt(0)
? ? bigX := big.NewInt(0)
? ? bigGcd.GCD(bigX,nil,bigP,bigBase)
? ? // x*bigP+y*bigBase=1?
? ? // => x*bigP = 1 modulo bigBase
? ? fmt.Println(bigX)
}

TA貢獻1810條經驗 獲得超4個贊
這是一種糟糕的風格,我應該有類似的東西嗎
WaitGroup
?
等待組解決了不同的問題。
一般來說,要在這里成為一個負責任的 go 公民并確保您的代碼運行并在其背后進行整理,您可能需要結合執行以下操作:
當在別處找到計算結果時,向生成的 goroutines 發出停止計算的信號。
確保同步進程在返回之前等待 goroutines 停止。如果它們正確響應#1 中的信號,這不是強制性的,但如果您不等待,則無法保證它們在父 goroutine 繼續之前已終止。
在執行此任務然后退出的示例程序中,絕對不需要執行任何操作。正如這條評論所指出的,您的程序的main
方法在找到滿意的答案后終止,此時程序將結束,所有 goroutine 將立即終止,并且操作系統將整理所有消耗的資源。等待 goroutines 停止是不必要的。
但是,如果您將這段代碼打包到一個庫中,或者它成為長期運行的“反素數計算”服務的一部分,那么最好整理您生成的 goroutine 以避免不必要地浪費周期。此外,一般來說,您可能還有其他場景,其中 goroutines 存儲狀態、持有外部資源的句柄或持有內部對象的句柄,如果沒有妥善整理,您就有泄漏的風險——最好適當地關閉這些。
傳達停止工作的要求
有幾種方法可以傳達這一點。我不認為這是一個詳盡的清單!(請在評論中或通過對帖子提出編輯建議來建議其他通用方法。)
使用特殊渠道
通過關閉為此目的保留的特殊“關閉”通道向子 goroutine 發出信號。這利用了通道公理:
來自關閉通道的接收立即返回零值
從關閉通道接收后,goroutine 應立即安排整理任何本地狀態并從函數返回。您之前的問題有實現此功能的示例代碼;該模式的一個版本是:
func myGoRoutine(shutdownChan <-chan struct{}) {
select {
case <-shutdownChan:
// tidy up behaviour goes here
return
// You may choose to listen on other channels here to implement
// the primary behaviour of the goroutine.
}
}
func main() {
shutdownChan := make(chan struct{})
go myGoRoutine(shutdownChan)
// some time later
close(shutdownChan)
}
在這種情況下,關閉邏輯被浪費了,因為該main()方法將在調用后立即返回close。這將與 goroutine 的關閉競爭,但我們應該假設它不會正確執行其整理行為。第 2 點解決了解決此問題的方法。
使用上下文
該context包提供了創建可以取消的上下文的選項。取消時,上下文Done()方法公開的通道將關閉,這標志著從 goroutine 返回的時間。
這種方法與之前的方法大致相同,除了更簡潔的封裝和上下文的可用性以傳遞給 goroutine 中的下游調用以在需要時取消嵌套調用。例子:
func myGoRoutine(ctx context.Context) {
select {
case <-ctx.Done():
// tidy up behaviour goes here
return
// Put real behaviour for the goroutine here.
}
}
func main() {
// Get a context (or use an existing one if you are provided with one
// outside a `main` method:
ctx := context.Background()
// Create a derived context with a cancellation method
ctx, cancel := context.WithCancel(ctx)
go myGoRoutine(ctx)
// Later, when ready to quit
cancel()
}
這與另一種情況有相同的錯誤,因為該main方法不會等待子 goroutines 在返回之前退出。
等待(或“加入”)子協程停止
上面示例中關閉關閉通道或關閉上下文的代碼不會等待子 goroutine 停止工作再繼續。這在某些情況下可能是可以接受的,而在其他情況下,您可能需要保證 goroutines 在繼續之前已經停止。
sync.WaitGroup可以用來實現這個要求。文檔很全面。等待組是一個計數器,它應該Add在啟動 goroutine 時使用它的方法遞增,并Done在 goroutine 完成時使用它的方法遞減。代碼可以通過調用其方法等待計數器歸零Wait,該方法會阻塞直到條件為真。對 的所有調用都Add必須在對 的調用之前發生Wait。
示例代碼:
func main() {
var wg sync.WaitGroup
// Increment the WaitGroup with the number of goroutines we're
// spawning.
wg.Add(1)
// It is common to wrap a goroutine in a function which performs
// the decrement on the WaitGroup once the called function returns
// to avoid passing references of this control logic to the
// downstream consumer.
go func() {
// TODO: implement a method to communicate shutdown.
callMyFunction()
wg.Done()
}()
// Indicate shutdown, e.g. by closing a channel or cancelling a
// context.
// Wait for goroutines to stop
wg.Wait()
}
有沒有更慣用的方法來進行這種計算?
通過以您定義的方式使用 goroutines,該算法當然可以并行化。由于工作受 CPU 限制,goroutines 對可用 CPU 數量的限制是有意義的(在機器上沒有其他工作的情況下)以從可用計算資源中獲益。
- 2 回答
- 0 關注
- 140 瀏覽
添加回答
舉報