9

C#で文字列をバイト[]配列に変換する最速の方法は何ですか? ソケットを介して大量の文字列データを送信しており、すべての操作を最適化する必要があります。現在、次を使用して送信する前に、文字列を byte[] 配列に変換します。

private static readonly Encoding encoding = new ASCIIEncoding();
//...
byte[] bytes = encoding.GetBytes(someString);
socket.Send(bytes);
//...
4

9 に答える 9

16

すべてのデータが実際ASCIIEncodingにASCIIになる場合は、さまざまな(完全に合理的な)ビットのエラー処理などがあるよりもわずかに高速に実行できる可能性があります。また、新しいバイトの作成を回避することでデータを高速化できる可能性があります。常に配列。すべてのメッセージの下にある上限があると仮定します。

void QuickAndDirtyAsciiEncode(string chars, byte[] buffer)
{
    int length = chars.Length;
    for (int i = 0; i < length; i++)
    {
        buffer[i] = (byte) (chars[i] & 0x7f);
    }
}

次に、次のようなことを行います。

readonly byte[] Buffer = new byte[8192]; // Reuse this repeatedly
...
QuickAndDirtyAsciiEncode(text, Buffer);
// We know ASCII takes one byte per character
socket.Send(Buffer, text.Length, SocketFlags.None);

しかし、これはかなり必死の最適化です。これがボトルネックであることが証明されるまで(または、少なくともこの種の粗雑なハックが役に立たないことを証明ASCIIEncodingするまで)、私は固執します。

于 2009-08-26T22:47:13.247 に答える
9

今のやり方で十分だと思います。そのような非常に低レベルの最適化に本当に関心がある場合は、Reflector を入手することをお勧めします。Reflector を使用すると、(ほとんどの場合) 自分でコードを見て、アルゴリズムが何であるかを確認できます。Reflector に表示されない場合は、いつでも Microsoft の SSCLI (Shared Source Common Language Infrastructure) をダウンロードして、MethodImplOptions.InternalCall メソッドの背後にある C++ コードを確認できます。

参考までに、Encoding.ASCII.GetBytes の実際の実装を次に示します。

public override int GetBytes(string chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
{
    if ((chars == null) || (bytes == null))
    {
        throw new ArgumentNullException();
    }
    if ((charIndex < 0) || (charCount < 0))
    {
        throw new ArgumentOutOfRangeException();
    }
    if ((chars.Length - charIndex) < charCount)
    {
        throw new ArgumentOutOfRangeException();
    }
    if ((byteIndex < 0) || (byteIndex > bytes.Length))
    {
        throw new ArgumentOutOfRangeException();
    }
    if ((bytes.Length - byteIndex) < charCount)
    {
        throw new ArgumentException();
    }
    int num = charIndex + charCount;
    while (charIndex < num)
    {
        char ch = chars[charIndex++];
        if (ch >= '\x0080')
        {
            ch = '?';
        }
        bytes[byteIndex++] = (byte) ch;
    }
    return charCount;
}
于 2009-08-26T22:34:09.323 に答える
1

何を最適化しようとしていますか?CPU?帯域幅?

帯域幅を最適化する場合は、事前に文字列データを圧縮してみてください。

まず、コードのプロファイリングを行い、遅いビットが何であるかを把握してから、そのような低レベルで最適化を試みます。

于 2009-08-26T22:40:26.113 に答える
1

GetBytes() 関数は、このためにすでに十分に最適化されていると思います。既存のコードの速度を改善するための提案は思いつきません。

編集 - ご存知のように、これがより速いかどうかはわかりません。しかし、BinaryFormatter を使用した別の方法を次に示します。

BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, someString);
byte[] bytes =  ms.ToArray();
ms.Close();
socket.Send(bytes);

これがより高速であると私が考える理由は、エンコードのステップをスキップするためです。また、これが適切に機能するかどうかも完全にはわかりません。しかし、あなたはそれを試して見るかもしれません。もちろん、ASCII エンコーディングが必要な場合、これは役に立ちません。

ちょうど別の考えがありました。このコードは、ASCII エンコーディングで GetBytes を使用するよりも 2 倍のバイト数を返すと思います。その理由は、.NET のすべての文字列がバックグラウンドで Unicode を使用しているためです。もちろん、Unicode は 1 文字あたり 2 バイトを使用しますが、ASCII は 1 バイトしか使用しません。したがって、BinaryFormatter は、ソケット経由で送信するデータの量を 2 倍にするため、この場合はおそらく使用するものではありません。

于 2009-08-26T22:34:22.630 に答える
1

同時実行要件 (またはその他) の手がかりがない場合: ThreadPool で文字列をバイト配列に変換してキューにドロップするスレッドをいくつか生成し、キューを監視してデータを送信するスレッドをもう 1 つ持つことができますか?

于 2009-08-27T00:44:16.873 に答える
0

他の人が言ったように、Encoding クラスは既にそのタスク用に最適化されているため、おそらく高速化するのは難しいでしょう。実行できるマイクロ最適化が 1 つありEncoding.ASCIIますnew ASCIIEncoding()。しかし、誰もが知っているように、マイクロ最適化は良くありません ;)

于 2009-08-26T22:41:19.653 に答える
0

もう 1 つのヒント: 最初の文字列をどのように作成するかはわかりませんが、StringBuilder.Append("something") は myString += "something" のようなものよりも本当に高速であることを覚えておいてください。

文字列を作成し、ソケット接続を介して送信するプロセス全体で、ボトルネックが文字列のバイト配列への変換であるとしたら、私は驚かれることでしょう。しかし、誰かがこれをプロファイラーでテストしてくれるかどうか、私は非常に興味があります。

于 2009-10-08T11:47:27.580 に答える
0

あなたが何をしているかをプロファイリングすることをお勧めします。文字列をバイト配列に変換する速度が、ソケット自体の速度よりもスループットにおいて大きな問題であるとは思えません。

于 2009-08-27T01:48:17.873 に答える