1

一時的な保存のために内部的にバッファを多用するパッケージを書いています。1024 個の要素から始めて、必要に応じて 2 倍に拡大する単一のグローバル (エクスポートされていない) バイト スライスがあります。

ただし、私のパッケージのユーザーが、大きなバッファーが割り当てられるような方法でパッケージを使用する可能性が非常に高いですが、その後パッケージの使用を停止し、割り当てられたヒープ スペースを大量に浪費する可能性があり、私には方法がありません。バッファを解放するかどうかを知る (または、これは Go であるため、GC にします)。

私は 3 つの可能な解決策を考えましたが、どれも理想的ではありません。私の質問は次のとおりです。これらの解決策のいずれか、またはおそらく私が考えていなかった解決策は、このような状況での標準的な方法ですか? 標準的な慣行はありますか?他のアイデアはありますか?

  1. ねじ込め。

しかたがない。これに対処するのは非常に困難であり、割り当てられたメモリをそのままにしておくことはそれほど悪いことではありません。

このアプローチの問題は明らかです。問題は解決しません。

  1. 「終了しました」または「内部メモリ使用量を縮小する」機能をエクスポートしました。

パッケージによって使用される内部ストレージを解放する、ユーザーが呼び出すことができる関数をエクスポートします (インテリジェントに呼び出すことは明らかにユーザー次第です)。

このアプローチには 2 つの問題があります。第 1 に、ユーザーへのインターフェイスがより複雑になり、すっきりしなくなります。第二に、そのような関数をいつ呼び出すのが賢明なのかをユーザーが知ることは不可能または実用的ではない可能性があるため、とにかく役に立たない可能性があります。

  1. パッケージが一定期間使用されなくなった後にバッファーを解放するゴルーチンを実行するか、バッファーのサイズがしばらく増加していない場合は常にバッファーを縮小します (おそらく長さを半分にします)。

このアプローチの問題点は、主に、スケジューラに不要な負荷がかかることです。明らかに、単一のゴルーチンはそれほど悪くはありませんが、これが受け入れられた慣行である場合、インポートしたすべてのパッケージが内部でこれを行っているとうまくスケーリングできません。また、時間に敏感なアプリケーションを使用している場合、知らないうちにコードを実行したくない場合があります (つまり、関数が呼び出されていないときは、パッケージは何も動作していないと想定する場合があります。合理的な仮定、私は言うだろう)。

それで...何かアイデアはありますか?

注:ここで既存のプロジェクトを確認できます(関連するコードは数十行のみです)。

4

4 に答える 4

0

すべての操作の最後にバッファを再スライスできます。

buffer = buffer[:0]

次に、拡張extendAndSliceBufferする必要がある場合、関数は元のバッキング配列を使用できる可能性が最も高くなります。そうでない場合は、新しい割り当てに苦しむことになりますextendAndSliceBuffer

全体として、よりクリーンな解決策は、@jnml が言ったように実行し、ユーザーがパフォーマンスを気にする場合は独自のバッファーを渡すことだと思います。パフォーマンスを気にしない場合は、グローバル var を使用せず、必要に応じてバッファーを割り当て、範囲外になったら解放する必要があります。

于 2013-08-05T04:10:03.363 に答える
0

これに対する一般的なアプローチは、クライアントが既存の []byte (または何でも) を引数として呼び出し/関数/メソッドに渡せるようにすることです。例えば:

// The returned slice may be a sub-slice of dst if dst was large enough
// to hold the entire encoded block. Otherwise, a newly allocated slice
// will be returned. It is valid to pass a nil dst.
func Foo(dst []byte, whatever Bar) (ret []byte, err error)

別のアプローチは、キャ​​ッシュプールなどから新しい [] バイトを取得し(その概念の後の名前を好む場合)、クライアントに依存して、使用済みのバッファーをそのような「ごみ箱」に返すことです。

ところで:これについて考えると、あなたはそれを正しくやっています。[]byte バッファーを合理的に再利用できる場合、GC の負荷が軽減され、プログラムのパフォーマンスが向上する可能性があります。場合によっては、違いが重大になることがあります。

于 2013-08-04T21:42:50.103 に答える
0

スレッドセーフではない Go コードを書くのは、一般的に非常に悪い形式です。2 つの異なるゴルーチンが同時にバッファーを変更する関数を呼び出した場合、それらが終了したときにバッファーがどのような状態になるかは誰にもわかりません。割り当てのパフォーマンスがボトルネックであると判断した場合は、ユーザーにスクラッチ スペース バッファーを提供させてください。

于 2013-08-05T05:12:33.907 に答える