ホームページ  >  記事  >  バックエンド開発  >  go言語の拡張方法にはどのようなものがあるのでしょうか?

go言語の拡張方法にはどのようなものがあるのでしょうか?

青灯夜游
青灯夜游オリジナル
2023-01-16 16:11:581562ブラウズ

Go 言語の拡張方法には次のものが含まれます: 1. スライスの拡張: append を使用してスライスに要素を追加するときに、スライスのスペースが不十分な場合、スライスの拡張がトリガーされます; 2. マップの拡張。マップ拡張をトリガーする条件は 2 つあります: 1. 負荷係数が 6.5 より大きいとき、つまり、各バケットに格納されているキーと値のペアの平均数が 6.5 に達したとき、2. オーバーフローの数が 2^ より大きいとき15、つまりオーバーフロー数が 32768 を超えた場合。

go言語の拡張方法にはどのようなものがあるのでしょうか?

このチュートリアルの動作環境: Windows 7 システム、GO バージョン 1.18、Dell G3 コンピューター。

スライス拡張

トリガー

append を使用して要素をスライスに追加する場合、スライスのスペースが不十分な場合、スライス拡張がトリガーされます。

原則

拡張とは、実際には、より大きなメモリを再割り当てし、元のスライス データを新しいスライスにコピーし、新しいスライスに戻って、展開後のデータをそれに追加します。

メカニズム

V1.8 より前:

拡張容量の選択は次のルールに従います:

  • 元のスライスの場合容量が 1024 未満の場合、新しいスライスの容量は元の 2 倍に拡張されます。
  • 元のスライスの容量が 1024 以上の場合、新しいスライスの容量は元の 1.25 倍に拡張されます;
// 1.17及以前的版本中
// old指切片的旧容量, cap指期望的新容量
func growslice(old, cap int) int {
    newcap := old
    doublecap := newcap + newcap
    // 如果期望容量大于旧容量的2倍,则直接使用期望容量作为最终容量
    if cap > doublecap {
        newcap = cap
    } else {
        // 如果旧容量小于1024,则直接翻倍
        if old < 1024 {
            newcap = doublecap
        } else {
            // 每次增长大约1.25倍
            for 0 < newcap && newcap < cap {
                newcap += newcap / 4
            }
            if newcap <= 0 {
                newcap = cap
            }
        }
    }
    // 这里忽略了对齐操作
    return newcap
}

V1 .8 以降:

新しい拡張容量の選択は次のルールに従います: (より滑らかな拡張係数を持ちます)

  • If元のスライスの容量が 256 未満の場合、新しいスライスの容量は元の 2 倍に拡張されます。
  • 元のスライスの容量が 256 以上の場合、新しいスライスの容量は元の 2 倍に拡張されます。元の 新しい容量 = (元の容量 3*256)/4
// 只关心扩容规则的简化版growslice
func growslice(old, cap int) int {
    newcap := old
    doublecap := newcap + newcap
    if cap > doublecap {
        newcap = cap
    } else {
        const threshold = 256 // 不同点1
        if old < threshold {
            newcap = doublecap
        } else {
            for 0 < newcap && newcap < cap {
                newcap += (newcap + 3*threshold) / 4 // 不同点2
            }
            if newcap <= 0 {
                newcap = cap
            }
        }
    }
    return newcap
}

マップ拡張

トリガーするには 2 つの条件があります 拡張:

  • 負荷係数> 6.5、つまり、各バケットに格納されるキーと値のペアの平均数は 6.5 に達します。 IncrementExpansion

  • オーバーフロー数 > 2^15 の場合、つまり、オーバーフロー数が 32768 を超えた場合。 均等量拡張/再配置

注: オーバーフロー バケットの作成は拡張メカニズムに属しません

# #増分拡張

  • #負荷率が大きすぎる場合、新しいバケットスペースが開かれ、バケットの数は以前の数の 2 倍になります
  • 新しいスペースはバケットによって参照されます。古いスペースは古いバケットによって参照されました。
  • その後、古いバケット内のデータは、新しく開かれたバケットのスペースに徐々に移動されます
マップに数億のキー値が格納されている場合、一度の再配置では比較的大きな遅延が発生します。Go は段階的な再配置戦略を採用しています。つまり、マップがアクセスされるたびに

が再配置をトリガーします。 2 つのキーと値のペア が再配置されます。 oldbuckets 内のすべてのキーと値のペアが再配置されたら、oldbuckets を削除します。 #次の図は、完全にロードされたバケットを含むマップを示しています (説明の便宜上、図ではバケットの値の領域が省略されています):

##現在のマップには 7 つのキーと値のペアが保存されており、バケットは 1 つだけです。このときの負荷率は7>6.5となる。データが再度挿入されると、容量拡張

操作がトリガーされ、

容量拡張の後、新しい挿入キーが新しいバケットに書き込まれます。負荷率がトリガーされるため、オーバーフロー バケットは作成されないことに注意してください。8 番目のキーと値のペアが挿入されると、容量拡張

がトリガーされます。

スケマティック ダイアグラム展開後のは次のとおりです:

マップへの後続のアクセス操作によって移行がトリガーされ、古いバケット内のキーと値のペアが徐々に再配置されます。

移行完了後の図は次のとおりです。

# データ移行プロセス中、元のバケット内のキーと値のペアが存在します。新しいバケットの前、および新しく挿入されたキー 値のペアは、新しいバケットの最後に存在します。

同額

拡張/再配置

いわゆる同額拡張

は、実際には容量の拡張ではありません。バケットの数 変更なし。Increment

Expansion と同様の再配置アクションをやり直し、緩いキーと値のペアを再配置してバケットの使用率を高め、より高速なアクセスを確保します。 継続的な追加と削除などの極端なシナリオでは、キーと値のペアが少数のバケットに集中しているため、オーバーフロー バケットの数が増加しますが、負荷率は高くないため、オーバーフロー バケットの数は増加します。

上の図からわかるように、オーバーフロー バケットのほとんどは空であり、アクセス効率は低下します。とても貧乏になる。このとき、等倍の 拡張

が行われ、バケット数は変更されず、再編成後にオーバーフロー バケットの数が削減され、スペースが節約され、アクセス効率が向上します。

【関連する推奨事項: Go ビデオ チュートリアル

プログラミング教育

以上がgo言語の拡張方法にはどのようなものがあるのでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。