String.Contains (), String.IndexOf () 'dan daha hızlı mı?


111

Yaklaşık 2000 karakterlik bir dize tamponum var ve belirli bir dizge içerip içermediğini kontrol etmem gerekiyor.
Her web isteği için bir ASP.NET 2.0 web uygulamasında kontrol yapacak.

String.Contains yönteminin String.IndexOf yönteminden daha iyi performans gösterip göstermediğini bilen var mı ?

    // 2000 characters in s1, search token in s2
    string s1 = "Many characters. The quick brown fox jumps over the lazy dog"; 
    string s2 = "fox";
    bool b;
    b = s1.Contains(s2);
    int i;
    i = s1.IndexOf(s2);

Eğlenceli gerçek


14
Bunu web isteği başına bir milyar kez yapmanız gerekirse, bunun gibi şeylere bir göz atmaya başlarım. Başka herhangi bir durumda, rahatsız etmem, çünkü her iki yöntemde de harcanan zaman, ilk etapta HTTP isteğini almaya kıyasla büyük olasılıkla inanılmaz derecede önemsiz olacaktır.
mookid8000

2
Optimizasyonun anahtarlarından biri varsaymak yerine test etmektir, çünkü .NET sürümü, işletim sistemi, donanım, girdideki farklılıklar gibi birçok faktöre bağlı olabilir. Çoğu durumda başkaları tarafından yapılan test sonuçları sisteminizde çok farklı olabilir.
Slai

Yanıtlar:


174

Containsaramalar IndexOf:

public bool Contains(string value)
{
    return (this.IndexOf(value, StringComparison.Ordinal) >= 0);
}

CompareInfo.IndexOfSonuçta bir CLR uygulaması kullanan çağrıları .

CLR'de dizelerin nasıl karşılaştırıldığını görmek istiyorsanız, bu size gösterecektir ( CaseInsensitiveCompHelper'ı arayın ).

IndexOf(string)seçeneği yoktur ve Contains()Sıralı karşılaştırma kullanır (akıllı bir karşılaştırma yapmaya çalışmak yerine bayt bayt karşılaştırma, örneğin, e ile é).

Bu yüzden IndexOf, IndexOfdoğrudan kernel32.dll'den (reflektörün gücü!) FindNLSString kullanarak bir dizi aramasına gidildiği gibi marjinal olarak daha hızlı (teoride) olacaktır .

.NET 4.0 için güncellendi - IndexOf artık Sıralı Karşılaştırma kullanmadığından İçerir daha hızlı olabilir. Aşağıdaki yoruma bakın.


3
Bu cevap hiçbir yerde doğru değil, açıklama için buraya bir göz atın stackoverflow.com/posts/498880/revisions
pzaj

55
Cevabım 7 yaşında ve .NET 2 çerçevesine dayanıyor. Sürüm 4 IndexOf()gerçekten daha hızlı olacak olanı kullanıyor StringComparison.CurrentCultureve Contains()kullanıyor StringComparison.Ordinal. Ama gerçekte bahsettiğimiz hız farklılıkları çok küçük - önemli olan nokta biri diğerini çağırıyor ve İçeriyor dizine ihtiyacınız yoksa daha okunaklı. Başka bir deyişle, endişelenmeyin.
Chris S

21

Muhtemelen hiç önemli olmayacak. Coding Horror hakkındaki bu yazıyı okuyun;): http://www.codinghorror.com/blog/archives/001218.html


4
Patrona yalakalıyor muyuz ...? : D Yine de, bir http isteğini sunmak için geçen süreye kıyasla, kısa bir dizede arama yapmak, bir kez önemli değil.
Fowl

Çok eğlenceli bir okuma, ancak birleştirme ile ilgili ilk şikayetinin bellek kullanımı olması beni rahatsız ediyor, sonra yalnızca dizeleri birleştirmenin çeşitli yollarıyla harcanan zamanı test ediyor.
sab669

11

İçerir (s2) birçok kez (bilgisayarımda 10 kat) IndexOf (s2) 'den daha hızlıdır çünkü Contains, IndexOf'un varsayılan olarak yaptığı kültüre duyarlı aramadan daha hızlı olan StringComparison.Ordinal kullanır (ancak bu .net 4.0 http: //davesbox.com/archive/2008/11/12/breaking-changes-to-the-string-class.aspx ).

İçerir, testlerimde IndexOf (s2, StringComparison.Ordinal)> = 0 ile tam olarak aynı performansa sahip ancak daha kısa ve amacınızı netleştiriyor.



7

Gerçek bir vaka yürütüyorum (sentetik bir kıyaslamanın tersine)

 if("=,<=,=>,<>,<,>,!=,==,".IndexOf(tmps)>=0) {

karşı

 if("=,<=,=>,<>,<,>,!=,==,".Contains(tmps)) {

Sistemimin hayati bir parçası ve 131.953 kez çalıştırılıyor (teşekkürler DotTrace).

Ne kadar şaşırtıcı bir sürpriz olsa da , sonuç beklenenin tam tersi

  • IndexOf 533ms.
  • 266 ms içerir.

: - /

net çerçeve 4.0 (13-02-2012 için güncellendi)


1
Çünkü INTçok daha büyüktür BOOLve IndexOf>=0bir adımı daha neden
Eric Yin

3
´StringComparison.Ordinal´i kullanmayı unuttunuz
Davi Fiamenghi

6

Reflector kullanarak, Contains'in IndexOf kullanılarak uygulandığını görebilirsiniz. İşte uygulama.

public bool Contains(string value)
{
   return (this.IndexOf(value, StringComparison.Ordinal) >= 0);
}

So Contains, IndexOf'u doğrudan çağırmaktan muhtemelen biraz daha yavaştır, ancak gerçek performans için herhangi bir önemi olacağından şüpheliyim.


1
Evet, ancak indexof'u bool olarak kullanmak için, karşılaştırmayı işlevin dışında yapması gerekirdi. Bu, büyük olasılıkla İçerir ile aynı sonucu verir, değil mi?
Gonzalo Quero

1
Muhtemelen, ancak bir yöntem çağrısını kaydediyorsunuz (satır içi yapılamıyorsa). Dediğim gibi, muhtemelen hiçbir zaman önemli olmayacak.
Brian Rasmussen

6

Kodunuzu gerçekten mikro optimize etmek istiyorsanız, en iyi yaklaşımınız her zaman karşılaştırmadır.

.Net çerçevesi mükemmel bir kronometre uygulamasına sahiptir - System.Diagnostics.Stopwatch


Bu en iyisidir, ancak hızlı bir yaklaşım istiyorsanız, hata ayıklama oturumunda duraklat düğmesine basmanız yeterlidir. Kod kontrolünün en yavaş kısımda kabaca% 50 oranında durması muhtemeldir .
Jeremy Thompson

@JeremyThompson "hata ayıklamayı duraklat" yöntemini 10 kez tekrarlar ve kendinize bir profil oluşturucu
edindiniz

4

Biraz okumadan, başlık altında String.Contains yönteminin sadece String.IndexOf'u çağırdığı anlaşılıyor. Aradaki fark, String.Contains bir boole döndürürken, String.IndexOf, alt dizenin bulunamadığını gösteren (-1) ile bir tamsayı döndürür.

100.000 kadar yinelemeli küçük bir test yazmanızı ve kendiniz görmenizi öneririm. Tahmin etseydim, IndexOf'un biraz daha hızlı olabileceğini söylerdim ama söylediğim gibi sadece bir tahmin.

Jeff Atwood'un blogunda dizeler hakkında güzel bir makalesi var . Daha çok birleştirme ile ilgili ama yine de yardımcı olabilir.


3

Bunun için bir güncelleme gibi, bazı testler yapıyorum ve giriş dizenizin oldukça büyük olmasını sağlıyorum, ardından paralel Regex bulduğum en hızlı C # yöntemidir (hayal ettiğim birden fazla çekirdeğiniz olması koşuluyla)

Örneğin toplam eşleşme miktarını elde etmek -

needles.AsParallel ( ).Sum ( l => Regex.IsMatch ( haystack , Regex.Escape ( l ) ) ? 1 : 0 );

Bu yardımcı olur umarım!


1
Merhaba phild, ayrı bir iş parçacığında bunu tomasp.net/articles/ahocorasick.aspx'den bir sürümle güncelledi, bu , anahtar kelimelerinizin (iğnelerinizin) değişmemesini sağlamak çok daha hızlıdır.
gary

2

Ölçmek için Jon Skeet'in bu son baskısı gibi bir kıyaslama kitaplığı kullanın .

Caveat Emptor

Tüm (mikro) performans soruları gibi, bu, kullandığınız yazılımın sürümlerine, incelenen verilerin ayrıntılarına ve aramayı çevreleyen koda bağlıdır.

Tüm (mikro) performans soruları gibi, ilk adım, bakımı kolayca yapılabilen çalışan bir sürüm almak olmalıdır. Daha sonra kıyaslama, profil oluşturma ve ayarlama, tahmin etmek yerine ölçülen darboğazlara uygulanabilir.


Bu bağlantı soruyu cevaplayabilirken, cevabın temel kısımlarını buraya eklemek ve referans için bağlantıyı sağlamak daha iyidir. Bağlantılı sayfa değişirse, yalnızca bağlantı yanıtları geçersiz hale gelebilir.
Mike Stockdale

bağlantılı kütüphane, cevabın ana itici gücü değil, pek çoğundan yalnızca biridir. Kütüphanelerin kaynağını veya açıklamasını yayınlamanın yanıtı, bu siteyi veya dünyayı iyileştireceğini düşünmüyorum.
David Schmitt

3
-1; soru "String.Contains yönteminin String.IndexOf yönteminden daha iyi performans gösterip göstermediğini bilen var mı?" - cevabınız "bir karşılaştırma kitaplığı kullanın", yani temelde "Bilmiyorum, kendin yap", "bu duruma göre değişir", yani "bilmiyorum" ve "çalışan bir sürüm ve profil al" anlamına gelir Bu aynı zamanda "Bilmiyorum, kendin yap" anlamına gelir. Bu 'Jeopardy' değil - lütfen nasıl yapılır fikirlerine değil, sorulan soruya bir cevap verin - onların yeri yorumlardadır .

-7

Bunu okumaya devam eden herkes için indexOf (), contains () IE ile uyumlu olmadığından, çoğu kurumsal sistemde muhtemelen daha iyi performans gösterecektir!


12
yeni OutOfScopeException ();
Raphaël
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.