2

cStrings (データベースから取得したもの) から多くの NSString オブジェクトをできるだけ早く割り当てる必要があります。cStringUsingEncoding などは遅すぎます。cString の割り当てに比べて約 10 ~ 15 倍遅くなります。

ただし、NSString を使用して NSString を作成すると、cString の割り当てにかなり近づきます (1M の割り当てで約 1.2 秒)。編集: 文字列のコピーを使用するように割り当てを修正しました。

const char *n;
const char *s = "Office für iPad: Steve Ballmer macht Hoffnung";
NSString *str = [NSString stringWithUTF8String:s];
int len = strlen(s);
for (int i = 0; i<10000000; i++) {
    NSString *s = [[NSString alloc] initWithString:[str copy]];
    s = s;
}

cString 割り当てテスト (1M 割り当ての場合も約 1 秒):

for (int i = 0; i<10000000; i++) {
    n = malloc(len);
    memccpy((void*)n, s, 0, len) ;
    n = n;
    free(n);
}

しかし、私が言ったように、stringWithCString などを使用すると、桁違いに遅くなります。私が得ることができた最速は、initWithBytesNoCopy を使用することでした (約 8 秒、したがって、stringWithString と比較して 8 倍遅くなります):

NSString *so = [[NSString alloc] initWithBytesNoCopy:(void*)n length:len encoding:NSUTF8StringEncoding freeWhenDone:YES];

では、cStrings からの割り当てを高速化する別の魔法の方法はありますか? NSString をサブクラス化することも除外しません (もちろん、それがクラスター クラスであることはわかっています)。

編集:楽器では、NSString の CFStringUsingByteStream3 への呼び出しが根本的な問題であることがわかります。

編集 2: 根本的な問題は、instuments __CFFromUTF8 によるものです。ソース [1] を見るだけで、これは確かに非常に非効率的で、一部のレガシー ケースを処理しているようです。

https://www.opensource.apple.com/source/CF/CF-476.17/CFBuiltinConverters.c?txt

4

3 に答える 3

2

これは公正なテストではないように私には思えます。

  1. cString 割り当てテストは、バイト配列を割り当ててデータをコピーしているようです。変数定義が含まれていないため、確かなことはわかりません。

  2. NSString *s = [[NSString alloc] initWithString:str]; 既存の NSString (データは既に正しい形式になっています) を取得しており、保持カウントをインクリメントするだけかもしれません。コピーが強制されたとしても、データは既に正しいエンコーディングのままであり、コピーする必要があります。

  3. [NSString stringWithUTF8String:s]; UTF8 エンコーディングを処理し、1 つのエンコーディング (UTF8) から内部 NSString/CFString エンコーディングに変換する必要があります。使用されているメソッド (CFStreamUsingByteStream) は、複数のエンコーディング (UTF8/UTF16/UTF32/その他) をサポートしています。特殊な UTF8 のみのメソッドの方が高速である可能性がありますが、これは本当にパフォーマンス上の問題なのか、それとも単なる演習なのかという疑問につながります。

CFStringUsingByteStream3のソース コードは、このファイルにあります。

于 2013-10-09T21:24:46.057 に答える
1

マイクロベンチマークは大きな気晴らしになりますが、ほとんど役に立ちません。ただし、この場合、有効性があります。

とりあえず、文字列の作成がパフォーマンスの問題の本当の原因であると実際に測定したと仮定すると、実際の問題は、メモリ帯域幅をどのように減らすかというように表現することができます。それは本当にあなたの問題があるところだからです。大量のデータが新たに割り当てられたバッファにコピーされます。

あなたが発見したように、あなたができる最速の方法は、まったくコピーしないことです。 initWithBytesNoCopy:...まさにこのケースを解決するために存在します。したがって、元の文字列バッファーを保持し、NSStringそれを指すすべてのインスタンスを 1 つの結合単位として管理するデータ構造を作成する必要があります。

詳しく考えなくても、生のバッファを NSData インスタンスにカプセル化し、関連付けられたオブジェクトを使用して、文字列インスタンスからそのNSDataインスタンスへの強い参照を作成することができます。そうすれば、最後の文字列の割り当てが解除されると、NSData (および関連するメモリ) の割り当てが解除されます。


これが CoreData 風の ORM レイヤー用であるという詳細を追加すると (そして、いいえ、あなたの説明は本当にそのレベルの制御が必要なように聞こえるので、間違ったことを提案するつもりはありません)、そう思われるでしょう。上記のように、ORM レイヤーはこれらの文字列を管理するのに理想的な場所です。

また、FMDB のようなものを調査して、必要なカプセル化と追加機能 (および高速化のためのフック) を追加する柔軟性の両方を提供できるかどうかを確認することをお勧めします。

于 2013-10-09T20:47:06.440 に答える