String.Contains () เร็วกว่า String.IndexOf () หรือไม่


111

ฉันมีสตริงบัฟเฟอร์ประมาณ 2,000 อักขระและต้องการตรวจสอบบัฟเฟอร์ว่ามีสตริงเฉพาะหรือไม่
จะทำการตรวจสอบในเว็บแอป ASP.NET 2.0 สำหรับทุกการร้องขอ

มีใครรู้บ้างว่าเมธอด String.Containsทำงานได้ดีกว่าเมธอด String.IndexOfหรือไม่?

    // 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);

สนุกจริงๆ


14
หากคุณต้องการทำสิ่งนี้เป็นพันล้านครั้งต่อคำขอทางเว็บฉันจะเริ่มดูสิ่งต่างๆเช่นนี้ ไม่ว่าในกรณีอื่นฉันจะไม่กังวลเนื่องจากเวลาที่ใช้ในวิธีใดวิธีหนึ่งมักจะไม่มีนัยสำคัญอย่างไม่น่าเชื่อเมื่อเทียบกับการรับคำขอ HTTP ในตอนแรก
mookid8000

2
กุญแจสำคัญอย่างหนึ่งในการเพิ่มประสิทธิภาพคือการทดสอบแทนที่จะตั้งสมมติฐานเนื่องจากอาจขึ้นอยู่กับปัจจัยหลายอย่างเช่นเวอร์ชัน. NET, ระบบปฏิบัติการ, ฮาร์ดแวร์, ความแปรผันในอินพุต ฯลฯ ในหลายกรณีผลการทดสอบที่ทำโดยผู้อื่น อาจแตกต่างกันมากในระบบของคุณ
ไล

คำตอบ:


174

ContainsโทรIndexOf:

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

ซึ่งเรียกCompareInfo.IndexOfซึ่งในที่สุดก็ใช้การใช้งาน CLR

หากคุณต้องการดูการเปรียบเทียบสตริงใน CLR สิ่งนี้จะแสดงให้คุณเห็น (มองหาCaseInsensitiveCompHelper )

IndexOf(string)ไม่มีตัวเลือกและContains()ใช้การเปรียบเทียบแบบลำดับ (การเปรียบเทียบแบบไบต์ต่อไบต์แทนที่จะพยายามทำการเปรียบเทียบอย่างชาญฉลาดเช่น e กับé)

ดังนั้นIndexOfจะเร็วขึ้นเล็กน้อย (ในทางทฤษฎี) เมื่อIndexOfตรงไปที่การค้นหาสตริงโดยใช้ FindNLSString จาก kernel32.dll (พลังของตัวสะท้อน!)

อัปเดตสำหรับ. NET 4.0 - IndexOf ไม่ใช้ Ordinal Comparison อีกต่อไปดังนั้นการมีจึงเร็วขึ้น ดูความคิดเห็นด้านล่าง


3
คำตอบนี้ไม่มีที่ไหนใกล้ถูกต้องเพียงดูที่นี่stackoverflow.com/posts/498880/revisionsสำหรับคำอธิบาย
pzaj

55
คำตอบของฉันคือ 7 ปีและอิงตามกรอบ. NET 2 รุ่นที่ 4 IndexOf()ไม่แน่นอนใช้StringComparison.CurrentCultureและContains()การใช้งานStringComparison.Ordinalซึ่งจะเร็วขึ้น แต่จริงๆแล้วความแตกต่างของความเร็วที่เรากำลังพูดถึงคือนาที - ประเด็นคือสิ่งหนึ่งที่เรียกอีกอันหนึ่งและประกอบด้วยจะอ่านได้มากขึ้นหากคุณไม่ต้องการดัชนี กล่าวอีกนัยหนึ่งไม่ต้องกังวลกับมัน
Chris S

21

อาจจะไม่สำคัญเลย อ่านโพสต์นี้เกี่ยวกับ Coding Horror;): http://www.codinghorror.com/blog/archives/001218.html


4
ห่วยแตกถึงเจ้านายเรา ... ? : D คุณพูดถูกแล้วเมื่อเทียบกับเวลาที่ใช้ในการส่งคำขอ http การค้นหาด้วยสตริงสั้น ๆ ครั้งเดียวไม่สำคัญ
Fowl

การอ่านที่สนุกสนานมาก แต่มันรบกวนฉันการร้องเรียนครั้งแรกของเขาเกี่ยวกับการเชื่อมต่อคือการใช้หน่วยความจำจากนั้นเขาจะทดสอบเวลาที่ใช้กับวิธีต่างๆในการรวมสตริงเท่านั้น
sab669

11

ประกอบด้วย (s2) หลายเท่า (ในคอมพิวเตอร์ของฉัน 10 เท่า) เร็วกว่า IndexOf (s2) เนื่องจากมีใช้ StringComparison.Ordinal ที่เร็วกว่าการค้นหาที่ไวต่อวัฒนธรรมที่ IndexOf ทำตามค่าเริ่มต้น (แต่อาจมีการเปลี่ยนแปลงใน. net 4.0 http: //davesbox.com/archive/2008/11/12/breaking-changes-to-the-string-class.aspx )

มีประสิทธิภาพเหมือนกับ IndexOf (s2, StringComparison.Ordinal)> = 0 ในการทดสอบของฉัน แต่สั้นกว่าและทำให้เจตนาของคุณชัดเจน


2
เห็นได้ชัดว่าการเปลี่ยนแปลงใน. NET 4.0 ถูกเปลี่ยนกลับก่อนที่มันจะไป RTM ดังนั้นฉันจะไม่พึ่งพาบทความนั้นมากเกินไปblogs.msdn.com/bclteam/archive/2008/11/04/…
Stephen Kennedy

7

ฉันใช้งานเคสจริง (ตรงข้ามกับเกณฑ์มาตรฐานสังเคราะห์)

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

กับ

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

เป็นส่วนสำคัญในระบบของฉันและมีการดำเนินการ 131,953 ครั้ง (ขอบคุณ DotTrace)

อย่างไรก็ตามความประหลาดใจที่น่าตกใจผลลัพธ์กลับตรงกันข้ามกับที่คาดไว้

  • ดัชนี 533 มิลลิวินาที
  • ประกอบด้วย 266ms

: - /

net framework 4.0 (อัปเดตเมื่อวันที่ 13-02-2555)


1
เพราะINTมีขนาดใหญ่กว่าBOOLมากและIndexOf>=0ทำให้เกิดขึ้นอีกขั้น
Eric Yin

3
คุณลืมใช้´StringComparison.Ordinal´
Davi Fiamenghi

6

คุณจะเห็นได้ว่ามีการใช้งานตัวสะท้อนแสงโดยใช้ IndexOf นี่คือการใช้งาน

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

ดังนั้นจึงมีแนวโน้มที่จะช้ากว่าการเรียก IndexOf โดยตรงเล็กน้อย แต่ฉันสงสัยว่ามันจะมีความสำคัญต่อประสิทธิภาพที่แท้จริง


1
ใช่ แต่ในการใช้ indexof เป็นบูลเขาจะต้องทำการเปรียบเทียบนอกฟังก์ชัน ส่วนใหญ่จะให้ผลลัพธ์เช่นเดียวกับที่มีใช่ไหม
Gonzalo Quero

1
อาจเป็นไปได้ แต่คุณจะบันทึกการเรียกใช้วิธีการหนึ่ง (เว้นแต่จะสามารถอินไลน์ได้) อย่างที่ฉันพูดมันอาจจะไม่สำคัญ
Brian Rasmussen

6

หากคุณต้องการเพิ่มประสิทธิภาพโค้ดของคุณอย่างแท้จริงแนวทางที่ดีที่สุดของคุณคือการเปรียบเทียบเสมอ

net framework มีการใช้งานนาฬิกาจับเวลาที่ยอดเยี่ยม - System.Diagnostics.Stopwatch


เป็นวิธีที่ดีที่สุดแต่ถ้าคุณต้องการแนวทางที่รวดเร็วเพียงแค่กดปุ่มหยุดชั่วคราวในเซสชันการดีบัก การควบคุมรหัสมีแนวโน้มที่จะหยุดการในส่วนที่ช้าที่สุดประมาณ 50% ของเวลา
Jeremy Thompson

@JeremyThompson ทำซ้ำวิธี "หยุดดีบัก" เช่น 10 ครั้งและคุณมีโปรไฟล์เป็นตัวเอง
Xeuron

4

จากการอ่านเล็กน้อยดูเหมือนว่าภายใต้ฝากระโปรงวิธีการ String.Contains เพียงแค่เรียก String.IndexOf ความแตกต่างคือ String.Contains ส่งคืนบูลีนในขณะที่ String.IndexOf ส่งคืนจำนวนเต็มโดยมี (-1) แทนว่าไม่พบสตริงย่อย

ฉันขอแนะนำให้เขียนการทดสอบเล็กน้อยโดยมีการทำซ้ำประมาณ 100,000 ครั้งและดูด้วยตัวคุณเอง ถ้าจะให้เดาก็คงบอกว่า IndexOf อาจจะเร็วกว่าเล็กน้อย แต่ก็อย่างที่บอกว่าเป็นแค่การเดา

Jeff Atwood มีบทความที่ดีในสายที่บล็อกของเขา เป็นข้อมูลเพิ่มเติมเกี่ยวกับการเรียงต่อกัน แต่อาจเป็นประโยชน์


3

เช่นเดียวกับการอัปเดตสิ่งนี้ฉันได้ทำการทดสอบบางอย่างและให้สตริงอินพุตของคุณมีขนาดค่อนข้างใหญ่จากนั้น Regex แบบขนานเป็นวิธี C # ที่เร็วที่สุดที่ฉันพบ (หากคุณมีมากกว่าหนึ่งคอร์ที่ฉันคิด)

รับจำนวนการแข่งขันทั้งหมดเช่น -

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

หวังว่านี่จะช่วยได้!


1
สวัสดี phild ในเธรดแยกได้อัปเดตสิ่งนี้ด้วยเวอร์ชันจากtomasp.net/articles/ahocorasick.aspxซึ่งการให้คำหลักของคุณ (เข็ม) ไม่เปลี่ยนแปลงนั้นเร็วกว่ามาก
gary

2

ใช้ไลบรารีมาตรฐานเช่นการโจมตีล่าสุดจาก Jon Skeetเพื่อวัดผล

Caveat Emptor

เนื่องจากคำถามเกี่ยวกับประสิทธิภาพ (ไมโคร) ทั้งหมดนี้ขึ้นอยู่กับเวอร์ชันของซอฟต์แวร์ที่คุณใช้รายละเอียดของข้อมูลที่ตรวจสอบและรหัสรอบ ๆ การโทร

สำหรับคำถามเกี่ยวกับประสิทธิภาพ (micro-) ทั้งหมดขั้นตอนแรกต้องได้รับเวอร์ชันที่ใช้งานได้ซึ่งดูแลรักษาได้ง่าย จากนั้นการเปรียบเทียบการสร้างโปรไฟล์และการปรับแต่งสามารถนำไปใช้กับคอขวดที่วัดได้แทนการคาดเดา


แม้ว่าลิงก์นี้อาจตอบคำถามได้ แต่ควรรวมส่วนสำคัญของคำตอบไว้ที่นี่และระบุลิงก์เพื่อการอ้างอิง คำตอบแบบลิงก์เท่านั้นอาจไม่ถูกต้องหากหน้าที่เชื่อมโยงเปลี่ยนไป
Mike Stockdale

ไลบรารีที่เชื่อมโยงเป็นเพียงหนึ่งในจำนวนมากและไม่ใช่แรงผลักดันหลักของคำตอบ ฉันไม่คิดว่าการโพสต์แหล่งที่มาของไลบรารีหรือคำอธิบายจะช่วยเพิ่มคำตอบไซต์นี้หรือทั่วโลก
David Schmitt

3
-1; คำถามคือ "มีใครรู้บ้างว่าเมธอด String.Contains ทำงานได้ดีกว่าเมธอด String.IndexOf หรือไม่" - คำตอบของคุณคือ "ใช้ไลบรารีมาตรฐาน" ซึ่งโดยทั่วไปหมายถึง "ฉันไม่รู้ทำเอง" "ขึ้นอยู่กับ" ซึ่งหมายถึง "ฉันไม่รู้" และ "รับเวอร์ชันและโปรไฟล์ที่ทำงานอยู่" ซึ่งหมายความว่า "ฉันไม่รู้ทำเอง" นี้ไม่ได้เป็น 'อันตราย' - โปรดให้คำตอบ กับคำถามที่ถามไม่ได้วิธีการ คิด - สถานที่ที่พวกเขาอยู่ในการแสดงความคิดเห็น

-7

สำหรับใครที่ยังอ่านสิ่งนี้อยู่ indexOf () น่าจะทำงานได้ดีกว่าในระบบขององค์กรส่วนใหญ่เนื่องจากมี () เข้ากับ IE ไม่ได้!


12
โยน OutOfScopeException ใหม่ ();
Raphaël
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.