String เทียบกับ StringBuilder


215

ฉันเข้าใจความแตกต่างระหว่างStringและStringBuilder( StringBuilderไม่แน่นอน) แต่มีประสิทธิภาพแตกต่างกันมากระหว่างทั้งสองหรือไม่

โปรแกรมที่ฉันกำลังใช้งานมีสตริงตัวเรือนจำนวนมากต่อท้าย (500+) ใช้StringBuilderตัวเลือกที่ดีกว่าไหม?

คำตอบ:


236

ใช่ความแตกต่างด้านประสิทธิภาพนั้นสำคัญมาก ดูบทความ KB " วิธีการปรับปรุงประสิทธิภาพการต่อสตริงใน Visual C # "

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

โชคดีที่มันค่อนข้างตรงไปตรงมาในการเรียกใช้การวิเคราะห์ประสิทธิภาพบนโค้ดของคุณเพื่อดูว่าคุณใช้เวลาStringBuilderอยู่ที่ไหน


44
กฎง่ายๆคือการใช้ Strings เมื่อคุณจะไม่เปลี่ยนและใช้ StringBuilder ถ้าคุณจะเปลี่ยน
ทิม

31
ฉันชอบคำตอบนี้มากโดยเฉพาะคำแนะนำในการเขียนโค้ดเพื่อความชัดเจนก่อนการแสดง ในฐานะนักพัฒนาเราใช้เวลาในการอ่านรหัสมากเท่าที่เราเขียน
Scott Lawrence

Outlaw: ฉันคิดว่ามันควรจะเป็นคำตอบของตัวเองที่ลงคะแนนแยกต่างหากถ้าฉันเข้าใจ StackOverflow อย่างถูกต้อง
Jay Bazuzi

2
บนพื้นฐานของประสบการณ์ของฉันถ้าคุณพยายามที่จะเชื่อมต่อประมาณ 10-15 สตริงคุณสามารถไปกับสตริง แต่ถ้าไม่มี ของสตริงเป็นมากกว่านั้นใช้ตัวสร้างสตริง
Peeyush

3
มันยังคงขึ้นอยู่กับวิธีการใช้งานสำหรับการอ้างอิงถึงการทดสอบจริง ๆ แล้วฉันชอบCoding Horror - โศกนาฏกรรมเศร้าของโรงละคร Micro-Optimization
Erik Philips

56

เพื่อชี้แจงสิ่งที่กิลเลียนพูดเกี่ยวกับสาย 4 ถ้าคุณมีสิ่งนี้:

string a,b,c,d;
 a = b + c + d;

จากนั้นมันจะเร็วขึ้นโดยใช้สตริงและตัวดำเนินการบวก นี่เป็นเพราะ (เช่น Java, ตามที่ Eric ชี้ให้เห็น), มันใช้ StringBuilder ภายในโดยอัตโนมัติ (ที่จริงแล้ว, มันใช้ primitive ที่ StringBuilder ใช้เช่นกัน)

อย่างไรก็ตามหากสิ่งที่คุณกำลังทำอยู่ใกล้กับ:

string a,b,c,d;
 a = a + b;
 a = a + c;
 a = a + d;

จากนั้นคุณต้องใช้ StringBuilder อย่างชัดเจน .Net ไม่ได้สร้าง StringBuilder ที่นี่โดยอัตโนมัติเพราะมันจะไม่มีจุดหมาย ในตอนท้ายของแต่ละบรรทัด "a" จะต้องเป็นสตริง (ไม่เปลี่ยนรูป) ดังนั้นมันจะต้องสร้างและกำจัด StringBuilder ในแต่ละบรรทัด สำหรับความเร็วคุณต้องใช้ StringBuilder เดียวกันจนกว่าคุณจะสร้างเสร็จ:

string a,b,c,d;
StringBuilder e = new StringBuilder();
 e.Append(b);
 e.Append(c);
 e.Append(d);
 a = e.ToString();

5
ไม่มีเหตุผลใดที่คอมไพเลอร์ C # ต้องปฏิบัติต่อตัวอย่างที่สองแตกต่างจากครั้งแรก โดยเฉพาะอย่างยิ่งไม่มีข้อผูกมัดในการสร้างสตริงในตอนท้ายของแต่ละบรรทัด คอมไพเลอร์อาจทำงานตามที่คุณพูด แต่ก็ไม่มีข้อผูกมัดที่จะทำเช่นนั้น
CodesInChaos

@CodesInChaos ตัวแปรสตริงที่ไม่เปลี่ยนรูปจะถูกกำหนดเป็นพิเศษที่ส่วนท้ายของแต่ละบรรทัดนั่นไม่ได้สร้างภาระหน้าที่ในการสร้างสตริงหรือไม่? อย่างไรก็ตามฉันเห็นด้วยกับจุดที่ไม่มีเหตุผลที่จะปฏิบัติต่อแต่ละบรรทัดที่แตกต่างกัน (และฉันไม่แน่ใจว่ามันจะ) การสูญเสียประสิทธิภาพมาจากการจัดสรรใหม่แม้ว่ามันจะไม่สำคัญ
Saeb Amini

@SaebAmini - หากaเป็นตัวแปรท้องถิ่นและวัตถุมันอ้างอิงไม่ได้รับการกำหนดให้กับตัวแปรอื่น ๆ บางคน (ที่อาจจะเข้าถึงได้ให้กับหัวข้ออื่น) เพิ่มประสิทธิภาพที่ดีสามารถกำหนดได้ว่าaจะไม่เข้าถึงได้จากรหัสอื่น ๆระหว่างขั้นตอนนี้ สาย; เฉพาะมูลค่าสุดท้ายของaเรื่อง a = b + c + d;ดังนั้นจึงสามารถรักษาบรรดาสามบรรทัดของรหัสราวกับว่าพวกเขาเขียน
ToolmakerSteve

29

StringBuilder จะดีกว่าถ้าคุณทำหลายลูปหรือส้อมในรหัสผ่านของคุณ ... อย่างไรก็ตามสำหรับประสิทธิภาพของ PURE หากคุณสามารถหลีกเลี่ยงได้ด้วยการประกาศสตริงเดี่ยวมันก็เป็นสิ่งที่มีประสิทธิภาพมากกว่า

ตัวอย่างเช่น:

string myString = "Some stuff" + var1 + " more stuff"
                  + var2 + " other stuff" .... etc... etc...;

มีประสิทธิภาพมากกว่า

StringBuilder sb = new StringBuilder();
sb.Append("Some Stuff");
sb.Append(var1);
sb.Append(" more stuff");
sb.Append(var2);
sb.Append("other stuff");
// etc.. etc.. etc..

ในกรณีนี้ StringBuild อาจถูกพิจารณาว่าสามารถบำรุงรักษาได้มากกว่า แต่ไม่ได้มีประสิทธิภาพมากกว่าการประกาศสตริงเดี่ยว

9 ครั้งจาก 10 แม้ว่า ... ใช้ตัวสร้างสตริง

ในหมายเหตุด้าน: string + var ยังมีประสิทธิภาพมากกว่าวิธีการ string.Format (โดยทั่วไป) ที่ใช้ StringBuilder ภายใน (เมื่อมีข้อสงสัย ... ตรวจสอบตัวสะท้อนแสง!)


17
ฉันหวังว่าคุณจะบอกว่าคุณรู้ได้อย่างไร / วิธีการตรวจสอบว่า
ChrisW

2
คุณไม่ได้ตรวจสอบประสิทธิภาพการทำงานของตัวสะท้อนแสง: คุณตรวจสอบประสิทธิภาพตามรหัสการจับเวลาเวลาวิเคราะห์ด้วยผู้สร้างโปรไฟล์และค้นหาคำอธิบายด้วยตัวสะท้อนสัญญาณ
Albin Sunnanbo

3
พิจารณาใช้ String.Format () เพื่อต่อเชื่อมสตริงขนาดเล็กจำนวนน้อยโดยเฉพาะอย่างยิ่งเป้าหมายคือการจัดรูปแบบข้อความเพื่อแสดงผู้ใช้
Gary Kindel

1
นี่เป็นข้อมูลที่แย่มาก ("สตริง myString มีประสิทธิภาพมากกว่า") ไม่เป็นความจริง แต่อย่างใด
Tom Stickel

3
ข้อมูลในคำตอบนี้ไม่ถูกต้อง StringBuilder เร็วกว่าการต่อข้อมูลในคำสั่งเดียวกันเล็กน้อย อย่างไรก็ตามคุณจะสังเกตเห็นความแตกต่างระหว่างทั้งสองถ้าคุณทำหลายร้อยหลายพันครั้ง ( ที่มา ) ดังที่ได้กล่าวไว้ในแหล่งข่าวว่า "มันไม่สำคัญเลย!"
David Sherret

25

ตัวอย่างง่ายๆที่แสดงให้เห็นถึงความแตกต่างของความเร็วเมื่อใช้การStringต่อข้อมูล VS StringBuilder:

System.Diagnostics.Stopwatch time = new Stopwatch();
string test = string.Empty;
time.Start();
for (int i = 0; i < 100000; i++)
{
    test += i;
}
time.Stop();
System.Console.WriteLine("Using String concatenation: " + time.ElapsedMilliseconds + " milliseconds");

ผลลัพธ์:

ใช้การเรียงต่อกันสตริง: 15423 มิลลิวินาที

StringBuilder test1 = new StringBuilder();
time.Reset();
time.Start();
for (int i = 0; i < 100000; i++)
{
    test1.Append(i);
}
time.Stop();
System.Console.WriteLine("Using StringBuilder: " + time.ElapsedMilliseconds + " milliseconds");

ผลลัพธ์:

ใช้ StringBuilder: 10 มิลลิวินาที

เป็นผลให้การทำซ้ำครั้งแรกใช้เวลา 15423 มิลลิวินาทีในขณะที่การทำซ้ำครั้งที่สองใช้StringBuilderเวลา 10 มิลลิวินาที

ฉันคิดว่าการใช้StringBuilderเร็วกว่ามากเร็วกว่ามาก


24

การเปรียบเทียบนี้แสดงให้เห็นว่าการต่อข้อมูลแบบปกตินั้นเร็วกว่าเมื่อรวม 3 หรือน้อยกว่าสตริง

http://www.chinhdo.com/20070224/stringbuilder-is-not-always-faster/

StringBuilder สามารถทำการปรับปรุงที่สำคัญมากในการใช้หน่วยความจำโดยเฉพาะอย่างยิ่งในกรณีของคุณเพิ่ม 500 สายเข้าด้วยกัน

ลองพิจารณาตัวอย่างต่อไปนี้:

string buffer = "The numbers are: ";
for( int i = 0; i < 5; i++)
{
    buffer += i.ToString();
}
return buffer;

เกิดอะไรขึ้นในความทรงจำ สตริงต่อไปนี้ถูกสร้างขึ้น:

1 - "The numbers are: "
2 - "0"
3 - "The numbers are: 0"
4 - "1"
5 - "The numbers are: 01"
6 - "2"
7 - "The numbers are: 012"
8 - "3"
9 - "The numbers are: 0123"
10 - "4"
11 - "The numbers are: 01234"
12 - "5"
13 - "The numbers are: 012345"

โดยการเพิ่มหมายเลขห้าเหล่านี้ไปยังจุดสิ้นสุดของสตริงเราสร้างวัตถุสตริง 13 รายการ! และ 12 คนนั้นไร้ประโยชน์! ว้าว!

StringBuilder แก้ไขปัญหานี้ ไม่ใช่ "สตริงที่ไม่แน่นอน" ตามที่เรามักจะได้ยิน ( สตริงทั้งหมดใน. NET จะไม่เปลี่ยนรูป ) มันทำงานได้โดยเก็บบัฟเฟอร์ภายในอาร์เรย์ของถ่าน Calling Append () หรือ AppendLine () เพิ่มสตริงลงในพื้นที่ว่างที่ท้ายอาร์เรย์ char; ถ้าอาร์เรย์มีขนาดเล็กเกินไปมันจะสร้างอาร์เรย์ใหม่ที่ใหญ่กว่าและคัดลอกบัฟเฟอร์ที่นั่น ดังนั้นในตัวอย่างข้างต้น StringBuilder อาจต้องการเพียงอาเรย์เดียวที่มีทั้งหมด 5 ส่วนเพิ่มเติมในสตริง - ขึ้นอยู่กับขนาดของบัฟเฟอร์ คุณสามารถบอก StringBuilder ได้ว่าบัฟเฟอร์ควรมีขนาดเท่าใดใน Constructor


2
ผู้เยาว์เล็กน้อย: มันแปลกที่จะพูดว่า "เราสร้างวัตถุสตริง 13 ชิ้นและวัตถุ 12 ชิ้นนั้นไร้ประโยชน์" แล้วบอกว่า StringBuilder สามารถแก้ไขปัญหานี้ได้ หลังจากทั้งหมดหกสายคุณไม่มีทางเลือกนอกจากการสร้าง; i.ToString()พวกเขามาจาก ดังนั้นด้วย StringBuilder คุณยังต้องสร้าง 6 + 1 สาย; มันลดการสร้าง 13 สายเพื่อสร้าง 7 สาย แต่นั่นก็ยังเป็นวิธีที่ผิดในการดู; การสร้างสตริงตัวเลขหกตัวนั้นไม่เกี่ยวข้องกัน Bottom line: คุณไม่ควรพูดถึงหกสายที่สร้างโดยi.ToString(); พวกเขาไม่ได้เป็นส่วนหนึ่งของการเปรียบเทียบประสิทธิภาพ
ToolmakerSteve

12

ใช่StringBuilderให้ประสิทธิภาพที่ดีขึ้นในขณะที่ทำการดำเนินการซ้ำผ่านสายอักขระ Stringมันเป็นเพราะการเปลี่ยนแปลงทั้งหมดที่จะทำเช่นเดียวเพื่อที่จะสามารถประหยัดเวลาได้มากแทนการสร้างอินสแตนซ์ใหม่เช่น

String Vs Stringbuilder

  • String

    1. ภายใต้Systemเนมสเปซ
    2. อินสแตนซ์ไม่เปลี่ยนรูป (อ่านอย่างเดียว)
    3. ประสิทธิภาพลดลงเมื่อมีการเปลี่ยนแปลงค่าอย่างต่อเนื่อง
    4. ด้ายปลอดภัย
  • StringBuilder (สตริงที่ไม่แน่นอน)

    1. ภายใต้System.Textเนมสเปซ
    2. อินสแตนซ์ที่ไม่แน่นอน
    3. แสดงประสิทธิภาพที่ดีขึ้นเนื่องจากมีการเปลี่ยนแปลงใหม่กับอินสแตนซ์ที่มีอยู่

ขอแนะนำบทความม็อบ dotnet: String Vs StringBuilder ใน C #

คำถาม Stack Overflow ที่เกี่ยวข้อง: ความผันแปรของสตริงเมื่อสตริงไม่เปลี่ยนแปลงใน C #? .


12

String Vs String Builder:

สิ่งแรกที่คุณต้องรู้ว่าในการประกอบสองชั้นนี้มีชีวิตอยู่ที่ไหน?

ดังนั้น,

สตริงมีอยู่ในSystemเนมสเปซ

และ

StringBuilderมีอยู่ในSystem.Textเนมสเปซ

สำหรับการประกาศสตริง :

คุณต้องรวมSystemเนมสเปซ อะไรแบบนี้ Using System;

และ

สำหรับการประกาศStringBuilder :

คุณต้องรวมSystem.textเนมสเปซ อะไรแบบนี้ Using System.text;

มาคำถามที่แท้จริง

ข้อแตกต่างระหว่างstring & StringBuilderคืออะไร

ความแตกต่างที่สำคัญระหว่างสองสิ่งนี้คือ:

สตริงไม่เปลี่ยนรูป

และ

StringBuilderไม่แน่นอน

ดังนั้นตอนนี้ให้พูดคุยถึงความแตกต่างระหว่างไม่เปลี่ยนรูปและไม่แน่นอน

ไม่แน่นอน::หมายถึง Changable

ไม่เปลี่ยนรูป::หมายถึงไม่สามารถเปลี่ยนแปลงได้

ตัวอย่างเช่น:

using System;

namespace StringVsStrigBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            // String Example

            string name = "Rehan";
            name = name + "Shah";
            name = name + "RS";
            name = name + "---";
            name = name + "I love to write programs.";

            // Now when I run this program this output will be look like this.
            // output : "Rehan Shah RS --- I love to write programs."
        }
    }
}

ดังนั้นในกรณีนี้เราจะเปลี่ยนวัตถุเดียวกัน 5 เท่า

ดังนั้นคำถามที่ชัดเจนคือ! เกิดอะไรขึ้นภายใต้ประทุนเมื่อเราเปลี่ยนสายเดียวกัน 5 ครั้ง

นี่คือสิ่งที่เกิดขึ้นเมื่อเราเปลี่ยนสตริงเดียวกัน 5 ครั้ง

ลองดูที่รูป

ป้อนคำอธิบายรูปภาพที่นี่

ชี้แจง:

เมื่อเราเริ่มต้นตัวแปร "ชื่อ" นี้เป็น "Rehan" เช่นstring name = "Rehan" ตัวแปรนี้ถูกสร้างขึ้นในสแต็ก "ชื่อ" และชี้ไปที่ค่า "Rehan" หลังจากเรียกใช้งานบรรทัดนี้: "name = name +" Shah "ตัวแปรอ้างอิงไม่ได้ชี้ไปที่วัตถุ" Rehan "อีกต่อไปตอนนี้มันชี้ไปที่" Shah "และอื่น ๆ

ดังนั้นstringความหมายที่เปลี่ยนไม่ได้คือเมื่อเราสร้างวัตถุในหน่วยความจำเราจะไม่สามารถเปลี่ยนวัตถุได้

ดังนั้นเมื่อเราทำการดัดแปลงnameตัวแปรวัตถุก่อนหน้ายังคงอยู่ในหน่วยความจำและวัตถุสตริงใหม่จะถูกสร้างขึ้น ...

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

ดังนั้นในกรณีของสตริงเมื่อใดก็ตามที่เราจัดการสตริงซ้ำแล้วซ้ำอีกเรามีวัตถุจำนวนมากที่สร้างขึ้นและยังคงอยู่ในหน่วยความจำ

นี่คือเรื่องราวของ String Variable

ตอนนี้ลองดูที่วัตถุ StringBuilder ตัวอย่างเช่น:

using System;
using System.Text;

namespace StringVsStrigBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            // StringBuilder Example

            StringBuilder name = new StringBuilder();
            name.Append("Rehan");
            name.Append("Shah");
            name.Append("RS");
            name.Append("---");
            name.Append("I love to write programs.");


            // Now when I run this program this output will be look like this.
            // output : "Rehan Shah Rs --- I love to write programs."
        }
    }
}

ดังนั้นในกรณีนี้เราจะเปลี่ยนวัตถุเดียวกัน 5 เท่า

ดังนั้นคำถามที่ชัดเจนคือ! เกิดอะไรขึ้นภายใต้ประทุนเมื่อเราเปลี่ยน StringBuilder เดียวกัน 5 เท่า

นี่คือสิ่งที่เกิดขึ้นเมื่อเราเปลี่ยน StringBuilder เดียวกัน 5 เท่า

ลองดูที่รูป ป้อนคำอธิบายรูปภาพที่นี่

คำอธิบาย: ในกรณีของวัตถุ StringBuilder คุณจะไม่ได้รับวัตถุใหม่ วัตถุเดียวกันจะเปลี่ยนในหน่วยความจำดังนั้นแม้ว่าคุณจะเปลี่ยนวัตถุและพูด 10,000 ครั้งเราก็จะยังคงมีเพียงวัตถุ stringBuilder

คุณไม่มีวัตถุขยะจำนวนมากหรือวัตถุ stringBuilder ที่ไม่ใช่ _referenced เพราะเหตุใดจึงสามารถเปลี่ยนแปลงได้ มันไม่แน่นอนหมายความว่ามันเปลี่ยนแปลงตลอดเวลา?

แตกต่าง:

  • String มีอยู่ใน System namespace โดยที่ Stringbuilder ปรากฏอยู่ใน System.Text namespace
  • สตริงที่ไม่เปลี่ยนรูปได้เป็น StringBuilder เป็น mutabe

8

StringBuilder ลดจำนวนการจัดสรรและการกำหนดค่าใช้จ่ายสำหรับหน่วยความจำเพิ่มเติมที่ใช้ ใช้อย่างถูกต้องสามารถลบความต้องการคอมไพเลอร์เพื่อจัดสรรสตริงที่มีขนาดใหญ่และใหญ่ขึ้นเรื่อย ๆ จนกว่าจะพบผลลัพธ์

string result = "";
for(int i = 0; i != N; ++i)
{
   result = result + i.ToString();   // allocates a new string, then assigns it to result, which gets repeated N times
}

เมื่อเทียบกับ

String result;
StringBuilder sb = new StringBuilder(10000);   // create a buffer of 10k
for(int i = 0; i != N; ++i)
{
   sb.Append(i.ToString());          // fill the buffer, resizing if it overflows the buffer
}

result = sb.ToString();   // assigns once

5

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

ที่มา: MSDN


3

StringBuilder ดีกว่าสำหรับการสร้างสตริงจากค่าที่ไม่คงที่จำนวนมาก

หากคุณกำลังสร้างสตริงจากค่าคงที่จำนวนมากเช่นค่าหลายบรรทัดในเอกสาร HTML หรือ XML หรือกลุ่มข้อความอื่น ๆ คุณสามารถหนีไปได้ด้วยการต่อท้ายสตริงเดียวกันเพราะคอมไพเลอร์เกือบทั้งหมดทำ "การพับอย่างต่อเนื่อง" ซึ่งเป็นกระบวนการลดทรีการแยกวิเคราะห์เมื่อคุณมีการจัดการอย่างต่อเนื่องมากมาย (มันยังใช้เมื่อคุณเขียนบางอย่างเช่นint minutesPerYear = 24 * 365 * 60) และสำหรับกรณีง่าย ๆ ที่มีค่าไม่คงที่ต่อท้ายซึ่งกันและกันคอมไพเลอร์. NET จะลดรหัสของคุณให้คล้ายกับสิ่งที่StringBuilderทำ

StringBuilderแต่เมื่อผนวกของคุณไม่สามารถจะลดลงไปสิ่งที่ง่ายโดยรวบรวมคุณจะต้องการ เมื่อ fizch ชี้ให้เห็นว่ามีแนวโน้มที่จะเกิดขึ้นภายในวง


2

ฉันเชื่อว่า StringBuilder เร็วขึ้นถ้าคุณมีมากกว่า 4 สายคุณต้องผนวกเข้าด้วยกัน นอกจากนี้ยังสามารถทำสิ่งที่ยอดเยี่ยมเช่น AppendLine


2

ใน. NET, StringBuilder ยังเร็วกว่าการผนวกสตริง ฉันค่อนข้างมั่นใจว่าใน Java พวกเขาเพิ่งสร้าง StringBuffer ภายใต้ประทุนเมื่อคุณต่อท้ายสตริงดังนั้นจึงไม่มีความแตกต่างจริงๆ ฉันไม่แน่ใจว่าทำไมพวกเขายังไม่ได้ทำใน. NET



2

ใช้สายสำหรับการเรียงต่อกันจะนำไปสู่ความซับซ้อน runtime O(n^2)ในคำสั่งของ

หากคุณใช้ a StringBuilderจะมีการคัดลอกหน่วยความจำน้อยกว่าที่ต้องทำ ด้วยการที่StringBuilder(int capacity)คุณสามารถเพิ่มประสิทธิภาพถ้าคุณสามารถประเมินว่าสุดท้ายStringจะเป็นอย่างไร แม้ว่าคุณจะไม่แม่นยำ แต่คุณก็อาจต้องเพิ่มขีดความสามารถStringBuilderเพียงสองสามครั้งเพื่อช่วยให้ประสิทธิภาพการทำงานดีขึ้น


2

ฉันได้เห็นประสิทธิภาพที่เพิ่มขึ้นอย่างมากจากการใช้EnsureCapacity(int capacity)การเรียกเมธอดบนอินสแตนซ์StringBuilderก่อนที่จะใช้มันสำหรับที่เก็บสตริง ฉันมักจะเรียกว่าในบรรทัดของรหัสหลังจากการเริ่มต้น มันมีผลเช่นเดียวกับถ้าคุณยกตัวอย่างStringBuilderเช่นนี้:

var sb = new StringBuilder(int capacity);

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


ไม่จำเป็นต้องโทรหาEnsureCapacityหลังจากเริ่มStringBuilderต้น เพียงแค่ยกตัวอย่างเช่นนี้StringBuilder var sb = new StringBuilder(int capacity)
David Ferenczy Rogožan

ฉันบอกว่ามันช่วยให้ใช้หมายเลขเฉพาะ
Karl Gjertsen

1

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

IMHO การต่อท้ายรายการสตริง 500+ รายการควรใช้ StringBuilder อย่างแน่นอน


1

String และ StringBuilder มีทั้งที่ไม่สามารถเปลี่ยนแปลงได้จริง StringBuilder สร้างขึ้นในบัฟเฟอร์ซึ่งทำให้ขนาดของมันสามารถจัดการได้อย่างมีประสิทธิภาพมากขึ้น เมื่อ StringBuilder จำเป็นต้องปรับขนาดคือเมื่อมีการจัดสรรใหม่บนฮีป โดยค่าเริ่มต้นมันมีขนาด 16 ตัวอักษรคุณสามารถตั้งค่านี้ในตัวสร้าง

เช่น.

StringBuilder sb = ใหม่ StringBuilder (50);


2
ไม่แน่ใจว่าคุณเข้าใจความหมายที่ไม่เปลี่ยนแปลง สตริงไม่เปลี่ยนรูปพวกเขาไม่สามารถเปลี่ยนแปลงได้ สิ่งที่ "เปลี่ยนแปลง" นั้นจริง ๆ แล้วเพียงว่าค่าเก่ายังคงอยู่ในกองโดยไม่มีตัวชี้ใด ๆ เพื่อค้นหา StringBuilder (ไม่แน่นอน) เป็นประเภทการอ้างอิงบนฮีปตัวชี้ไปยังฮีปจะถูกเปลี่ยนและการจัดสรรพื้นที่สำหรับการเปลี่ยนแปลงนี้
Tom Stickel

1

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

หากคุณไม่ต้องการซิงโครไนซ์หรือใช้งานเธรดอย่างปลอดภัยให้ไปที่ StringBuilder สิ่งนี้จะเร็วกว่าการต่อข้อมูลสตริงและเร็วกว่า StringBuffer เนื่องจากไม่มีค่าใช้จ่ายในการซิงโครไนซ์


0

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


0

หากคุณกำลังต่อเชื่อมสตริงจำนวนมากใช้ StringBuilder เมื่อคุณต่อสตริงเข้าด้วยกันคุณจะสร้างสตริงใหม่ทุกครั้งโดยใช้หน่วยความจำมากขึ้น

อเล็กซ์


0

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


0

วิธีการของฉันคือการใช้ StringBuilder ตลอดเวลาเมื่อทำการต่อสาย 4 ตัวหรือมากกว่านั้นหรือเมื่อฉันไม่รู้ว่าการต่อเรียงจะเกิดขึ้นได้อย่างไร

บทความที่ดีเกี่ยวกับประสิทธิภาพที่ดีอยู่ที่นี่


0

StringBuilder มีประสิทธิภาพมากขึ้นอย่างมีนัยสำคัญ แต่คุณจะไม่เห็นประสิทธิภาพนั้นเว้นแต่ว่าคุณกำลังทำการแก้ไขสตริงจำนวนมาก

ด้านล่างนี้เป็นโค้ดสั้น ๆ เพื่อเป็นตัวอย่างของประสิทธิภาพ อย่างที่คุณเห็นคุณเริ่มเห็นการเพิ่มขึ้นอย่างมากเมื่อคุณทำซ้ำจำนวนมาก

อย่างที่คุณเห็นการทำซ้ำ 200,000 ครั้งใช้เวลา 22 วินาทีในขณะที่การใช้ซ้ำ 1 ล้านครั้งStringBuilderนั้นเกือบจะทันที

string s = string.Empty;
StringBuilder sb = new StringBuilder();

Console.WriteLine("Beginning String + at " + DateTime.Now.ToString());

for (int i = 0; i <= 50000; i++)
{
    s = s + 'A';
}

Console.WriteLine("Finished String + at " + DateTime.Now.ToString());
Console.WriteLine();

Console.WriteLine("Beginning String + at " + DateTime.Now.ToString());

for (int i = 0; i <= 200000; i++)
{
    s = s + 'A';
}

Console.WriteLine("Finished String + at " + DateTime.Now.ToString());
Console.WriteLine();
Console.WriteLine("Beginning Sb append at " + DateTime.Now.ToString());

for (int i = 0; i <= 1000000; i++)
{
    sb.Append("A");
}
Console.WriteLine("Finished Sb append at " + DateTime.Now.ToString());

Console.ReadLine();

ผลลัพธ์ของโค้ดด้านบน:

String เริ่มต้น + ที่ 28/01/2013 16:55:40

สิ้นสุด String + ที่ 28/01/2013 16:55:40

String เริ่มต้น + ที่ 28/01/2013 16:55:40

สิ้นสุด String + ที่ 28/01/2013 16:56:02

การเริ่มต้น Sb ต่อท้ายเวลา 28/01/2013 16:56:02

เสร็จแล้ว Sb ต่อท้ายที่ 28/01/2013 16:56:02


1
ถ้า String builder มีพลังมากแล้วทำไมเราถึงมี String อยู่ ทำไมเราไม่ล้างสตริงให้สมบูรณ์ ฉันถามคำถามนี้เพื่อให้คุณสามารถบอกฉันถึงประโยชน์ของ String over StringBuilder
ไม่สามารถแตกได้

-2

StringBuilder จะทำงานได้ดีขึ้นจากจุดตั้งหน่วยความจำ สำหรับการประมวลผลความแตกต่างในช่วงเวลาของการดำเนินการอาจจะเล็กน้อย

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