ホームページ > バックエンド開発 > Golang > Go で大規模なストリーミング JSON を効率的にデコードするにはどうすればよいですか?

Go で大規模なストリーミング JSON を効率的にデコードするにはどうすればよいですか?

Mary-Kate Olsen
リリース: 2025-01-02 20:03:40
オリジナル
367 人が閲覧しました

How to Efficiently Decode Large Streaming JSON in Go?

Go でストリーミング JSON をデコードする方法

大規模な JSON 応答を処理する場合、デコードする前に応答全体をメモリにロードするのは理想的ではありません。 ioutil.ReadAll 関数を使用すると、大きな JSON ペイロードを処理するときにメモリの問題が発生する可能性があります。この記事では、メモリ消費の問題を回避しながら、JSON データをストリーミング中にオンザフライでデコードする方法について説明します。

json.Decoder を使用した JSON ストリーミング

Go 標準ライブラリの json.Decoder は、次のことを提供します。 JSON ストリームを段階的に解析する機能。これは、Decoder.Token() メソッドによって実現されます。

Decoder.Token() メソッドは、JSON ストリーム内の次のトークンを消費せずに返します。これにより、JSON データの選択的な解析とイベント駆動型の処理が可能になります。

JSON 構造の処理

イベント駆動型の解析では、JSON 構造内の現在の位置を追跡するステート マシンが必要です。このステート マシンを使用して、ストリームに表示される JSON データのさまざまな部分を処理できます。

たとえば、次の形式の JSON 応答を受信したとします:

{
    "property1": "value1",
    "property2": "value2",
    "array": [
        { "item1": "value3" },
        { "item2": "value4" }
    ]
}
ログイン後にコピー

この JSON ストリームを段階的に解析し、配列要素を個別に処理する関数を作成できます。

func processJSONStream(stream io.Reader) {
    decoder := json.NewDecoder(stream)

    state := "start"
    for decoder.More() {
        token, err := decoder.Token()
        if err != nil {
            log.Fatal(err)
        }

        switch state {
        case "start":
            if delim, ok := token.(json.Delim); ok && delim == '{' {
                state = "object"
            } else {
                log.Fatal("Expected object")
            }
        case "object":
            switch t := token.(type) {
            case json.Delim:
                if t == '}' {
                    // End of object
                    state = "end"
                } else if t == ',' {
                    // Next property
                    continue
                } else if t == '[' {
                    // Array found
                    state = "array"
                }

                if t == ':' {
                    // Property value expected
                    state = "prop_value"
                }
            case string:
                // Property name
                fmt.Printf("Property '%s'\n", t)
            default:
                // Property value
                fmt.Printf("Value: %v\n", t)
            }
        case "array":
            if delim, ok := token.(json.Delim); ok && delim == ']' {
                // End of array
                state = "object"
            } else if token == json.Delim('{') {
                // Array item object
                fmt.Printf("Item:\n")
                state = "item"
            }
        case "item":
            switch t := token.(type) {
            case json.Delim:
                if t == '}' {
                    // End of item object
                    fmt.Printf("\n")
                    state = "array"
                } else if t == ',' {
                    // Next item property
                    fmt.Printf(",\n")
                    continue
                }
            case string:
                // Item property name
                fmt.Printf("\t'%s'", t)
            default:
                // Item property value
                fmt.Printf(": %v", t)
            }
        case "prop_value":
            // Decode the property value
            var value interface{}
            if err := decoder.Decode(&value); err != nil {
                log.Fatal(err)
            }
            fmt.Printf("Value: %v\n", value)
            state = "object"
        }
    }
}
ログイン後にコピー

JSON 応答で呼び出された場合、この関数は、プロパティ名と値、配列内の個々の項目を出力します。

結論

イベント駆動型処理で json.Decoder と Decoder.Token() を使用すると、次のことが可能になります。大規模な JSON 応答を段階的に解析し、メモリ消費の問題を回避し、データがストリーミングされる際の効率的な処理を可能にします。

以上がGo で大規模なストリーミング JSON を効率的にデコードするにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート