-1

go は同時実行プログラム言語であるためchannel(ほとんどすべてのコードで使用しています)、または他のものを synchronous に使用しgoroutineます。

また、スケジューラを使用してスケジュールを設定することも知っていました。つまり、各ゴルーチンで (チャネル アクション、runtime.goSche など) を呼び出して、それが実行されることを保証する必要がありますgoroutinescheduler

上記は私の現在の制限事項であり、goそれらを使用してコードを設計しています。

しかし、コードでコードブロッキングが発生することもわかりました。また、ブロックの原因を見つけるのは困難です ( GDBを使用しても)。

私は何かを見逃していましたか?

ブロックの原因として他に何が考えられるでしょうか?

また、注意すべきことは何ですか?

[編集] : 私のプロジェクトのコードは少し大きいので、OK。標準 コードは表示せずgo、コード ブロッキングの原因となる可能性のある部分の一般的な考え方だけを示します。私のプロジェクトのファイル送信モジュールのコードの一部を次に示します。

func(c *client)listenRead() {
    for {
        _ := websocket.JSON.Receive(c.ws, &package)
        switch package.Op {
        case fileUpld:
            c.fileMan.store <- package.Body
        case fileDownld:
            c.fileMan.downld <- package.Body
        case c.xxx:
            ...
        default:
            // bad package.
        }
    }
}

クライアントは、別のクライアントから websocket を介してメッセージをリッスンして受信し、packageフィールドOpに従ってパッケージを別のhandlerに転送します。たとえば、以下にfileManager示します。

func(fm *fileManager) fileRouter() {
    for {
        select {
            case fs := <-fm.fileUpld:
                if window < filesize {
                    f.Write(fs.content) // client A write to file
                    window += fs.contSize
                } else {
                    f.close()           // close file
                }
            case fd := fm.downld:
                go fm.downldFile(fd)
        }
    }
}

から送信されたデータをchanfileMangerが取得すると、 はファイルの断片を受信して​​サーバーに保存できます。また、クライアントから を受信するとファイルをダウンロードでき、以下に示すジョブを実行するために を生成します。 fileUpldclientrequestgoroutine

func(fm *fileManager) downldFile(fd) {
    f := getFile(fd)                     // get the file that client A write
    b := make([]byte, SeqLength)
    for {
        if convergence < window {
            f.Read(b)

            // wrap 'b' to package 'p', for send

            fm.server.send <- p   // send to client B
        } else if window < fileSize {
            runtime.Goshed()
        } else {
            // download done.
            fm.done <- xx
            return
        }
    }
}

私のファイル送信モジュールの主なアイデアは、クライアントAがクライアント B にファイルを送信し、クライアントBacceptanceからのファイルを待ちたくないということです。つまり、最初にサーバーに保存し、クライアント Bが後でファイルを取得します。サーバーからダウンロードします。ただし、クライアント Aがファイルをアップロードしている間に、クライアント Bがファイルをダウンロードする可能性があります。したがって、アップロードとダウンロードの間に同期が必要です。

これを実装するために、 windowconvergencefilesizeの3 つの変数を使用します。クライアントAがファイルをアップロード(書き込み)すると、ウィンドウ書き込みバイトの値を増やします。クライアント Bがファイルをダウンロード (読み取り) すると、コンバージェンスによって読み取りバイト数が増加します。のみ発生する間のみ発生します。と同じように:Writewindow < filesizereadconvergence < window

+-----------+---------------+--------------+
|############||||||||||||||||              |
+-----------+---------------+--------------+
            ^               ^              ^
            |               |              |
       convergence        window        filesize

これによりデータ競合が発生することはわかっていましたが、まだ書き込まれていないreadコンテンツを読み取らないことも保証されます.(ところで:それを実装するために使用するソリューションはありません.)writechannel

アップロードとダウンロードを同時に行おうとすると、コードブロッキングが発生します(クライアントAを遅くして達成します)。しかし、2に設定すると問題ありませんGOMAXPROCS

4

1 に答える 1

0

「世界を止める」と呼ばれる、プログラム全体を一時停止するガベージ コレクターを検討する必要があります。大量のメモリを消費する大規模なアプリケーションでは、GC は最大 10 秒間「世界を停止」する可能性がありますが、これは最悪のケースです。Go でのGC に関する良い回答は次のとおりです。Goはどのような種類のガベージ コレクションを使用しますか?

于 2013-10-27T09:17:40.567 に答える