亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

計算模逆、

計算模逆、

Go
哆啦的時光機 2023-03-29 16:15:12
我想計算模運算中素數的逆元素。為了加快速度,我啟動了幾個 goroutine,它們試圖在一定范圍內找到元素。當第一個找到元素時,它將它發送到主 goroutine,此時我想終止程序。所以我調用close了主 goroutine,但我不知道 goroutines 是否會完成它們的執行(我猜不會)。于是出現了幾個問題:1)這是一種糟糕的風格,我應該有類似的東西嗎WaitGroup?2)是否有更慣用的方法來進行此計算?package mainimport "fmt"const (    Procs = 8    P     = 1000099    Base  = 1<<31 - 1)func compute(start, end uint64, finished chan struct{}, output chan uint64) {    for i := start; i < end; i++ {        select {        case <-finished:            return        default:            break        }        if i*P%Base == 1 {            output <- i        }    }}func main() {    finished := make(chan struct{})    output := make(chan uint64)    for i := uint64(0); i < Procs; i++ {        start := i * (Base / Procs)        end := (i + 1) * (Base / Procs)        go compute(start, end, finished, output)    }    fmt.Println(<-output)    close(finished)}
查看完整描述

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)

}


查看完整回答
反對 回復 2023-03-29
?
蝴蝶不菲

TA貢獻1810條經驗 獲得超4個贊

這是一種糟糕的風格,我應該有類似的東西嗎WaitGroup?

等待組解決了不同的問題。

一般來說,要在這里成為一個負責任的 go 公民并確保您的代碼運行并在其背后進行整理,您可能需要結合執行以下操作:

  1. 當在別處找到計算結果時,向生成的 goroutines 發出停止計算的信號。

  2. 確保同步進程在返回之前等待 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 數量的限制是有意義的(在機器上沒有其他工作的情況下)以從可用計算資源中獲益。


查看完整回答
反對 回復 2023-03-29
  • 2 回答
  • 0 關注
  • 140 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號