大きなJSONデータの解析は、本来よりも遅いようです。原因を特定し、Goの作成者にパッチを送信することは価値があります。
それまでの間、JSONを回避してバイナリ形式を使用できれば、この問題を回避できるだけではありません。また、コードが数値のASCII小数表現を同等のバイナリIEEE 754に解析するために費やしている時間も得られます(その際、丸め誤差が発生する可能性があります)。
送信者と受信者の両方がGoで記述されている場合は、Goのバイナリ形式を使用することをお勧めします: gob 。
簡単なテストを実行して、2000エントリのマップを生成し、各スライスに1050の単純なフロートを含めると、20 MBのJSONが得られます。これは、私のマシンで解析するのに1.16秒かかります。
これらのクイックベンチマークでは、3回の実行のうち最善を尽くしますが、t0 := time.Now()
を使用して、実際の解析時間のみを測定するようにしています。 Unmarshal呼び出しの前にtime.Now().Sub(t0)
を出力します その後。
GOBを使用すると、同じマップで18 MBのデータが生成され、解析に115ミリ秒かかります。
10分の1の時間 。
結果は、実際にフロートがいくつあるかによって異なります。フロートに有効数字がたくさんあり、float64表現に値する場合、20MBのJSONに含まれるフロートは200万よりはるかに少なくなります。その場合、JSONとGOBの違いはさらに大きくなります。
ところで、これは、問題が実際にJSONパーサーにあり、解析するデータの量にも、作成するメモリ構造にもないことを証明しています(どちらのテストも、最大20 MBのデータを解析し、フロートの同じスライスを再作成するためです)。 JSONですべてのfloatを文字列に置き換えると、解析時間が1.02秒になり、文字列表現からバイナリfloatへの変換には一定の時間がかかりますが(バイトを移動するだけの場合と比較して)、主な原因ではないことが確認されます。
送信者とパーサーの両方がGoでない場合、またはGOBよりもさらにパフォーマンスを向上させたい場合は、Protocol Buffersを使用するか、「encoding / binary」などを使用して手動で、独自にカスタマイズしたバイナリ形式を使用する必要があります。