سلسلة سلسلة غير آمنة في C #، تحتاج إلى استخدام stringbuilder؟

StackOverflow https://stackoverflow.com/questions/779051

سؤال

سؤالي هذا: هل سلسلة سلسلة في C # آمنة؟ إذا كانت تسلسل السلسلة تؤدي إلى أخطاء غير متوقعة، واستبدال تسلسل السلسلة باستخدام StringBuilder يؤدي تلك الأخطاء إلى أن تختفي تلك الأخطاء، فما الذي قد يشير إليه؟

خلفية: أقوم بتطوير تطبيق سطر قيادة صغير C #. يستغرق الأمر حجج سطر الأوامر، ويقوم بإجراء استعلام SQL معقدا قليلا، ويخرج حوالي 1300 صف بيانات في ملف XML منسق.

سيعمل برنامجي الأولي دائما بشكل جيد في وضع التصحيح. ومع ذلك، في وضع الإصدار، سيتصل في نتيجة SQL 750، ثم تموت مع وجود خطأ. الخطأ كان أنه لا يمكن قراءة عمود معين من البيانات، حتى من خلال قراءة () كائن SQLDTATEREADER قد عاد فقط صحيح.

تم إصلاح هذه المشكلة باستخدام StringBuilder لجميع العمليات في التعليمات البرمجية، حيث كان هناك سابقا كان هناك "String1 + String2". أنا لا أتحدث عن سلسلة سلسلة داخل حلقة الاستعلام SQL، حيث كان StringBuilder قيد الاستخدام بالفعل. أنا أتحدث عن استصلاحات بسيطة بين متغيرتين أو ثلاث متغيرات قصيرة في التعليمات البرمجية.

كان لدي الانطباع بأن C # كان ذكيا بما يكفي للتعامل مع إدارة الذاكرة لإضافة بعض الأوتار معا. هل أنا مخطئ؟ أم أن هذا يشير إلى بعض أنواع التعليمات البرمجية الأخرى؟

هل كانت مفيدة؟

المحلول

بصرف النظر عن ما تفعله من الأفضل القيام بأفضل مع XML و APIS بدلا من الأوتار أو Stringbuilder أشك في أن الخطأ الذي تراه هو بسبب سلسلة سلسلة. ربما التبديل إلى StringBuilder ملثمين فقط الخطأ أو ذهبت بأمان، لكنني أشك في استخدام السلاسل كانت حقا السبب.

نصائح أخرى

للإجابة على سؤالك:سلسلة التذهارية في C # (و .NET بشكل عام) هو "آمنة"، ولكن القيام بذلك في حلقة ضيقة حيث تصف من المرجح أن تسبب ضغط ذاكرة شديدة ووضع الضغط على جامع القمامة.

أود أن أخمن تخمين أن الأخطاء التي تتحدث عنها كانت مرتبطة باستنفاد الموارد من نوع ما، ولكن سيكون من المفيد أن تقدم المزيد من التفاصيل - على سبيل المثال، هل تلقيت استثناء؟ هل تم إنهاء التطبيق بشكل غير طبيعي؟

خلفية:.NET سلاسل ثابتة، لذلك عندما تقوم بسلسلة مثل هذا:

var stringList = new List<string> {"aaa", "bbb", "ccc", "ddd", //... };
string result = String.Empty;
foreach (var s in stringList)
{
    result = result + s;
}

هذا يعادل تقريبا ما يلي:

string result = "";
result = "aaa"
string temp1 = result + "bbb";
result = temp1;
string temp2 = temp1 + "ccc";
result = temp2;
string temp3 = temp2 + "ddd";
result = temp3;
// ...
result = tempN + x;

الغرض من هذا المثال هو التأكيد على أنه في كل مرة حول الحلقة يؤدي إلى تخصيص سلسلة مؤقتة جديدة.

نظرا لأن السلاسل غير قابلة للتغيير، لا يحتوي وقت التشغيل على خيارات بديلة ولكن لتخصيص سلسلة جديدة في كل مرة تقوم فيها بإضافة سلسلة أخرى إلى نهاية النتيجة.

على الرغم من أن result يتم تحديث السلسلة باستمرار للإشارة إلى أحدث وأكبر النتيجة الوسيطة، فأنت تنتج الكثير من هذه السلسلة المؤقتة غير المسماة هذه التي تصبح مؤهلة لجمع القمامة على الفور تقريبا.

في نهاية هذا التسليط، سيكون لديك السلاسل التالية المخزنة في الذاكرة (على افتراض، للبساطة، أن جامع القمامة لم يعمل بعد).

string a = "aaa";
string b = "bbb";
string c = "ccc";
// ...
string temp1 = "aaabbb";
string temp2 = "aaabbbccc";
string temp3 = "aaabbbcccddd";
string temp4 = "aaabbbcccdddeee";
string temp5 = "aaabbbcccdddeeefff";
string temp6 = "aaabbbcccdddeeefffggg";
// ...

على الرغم من أن كل هذه المتغيرات المؤقتة الضمنية مؤهلة لجمع القمامة على الفور تقريبا، إلا أنهم لا يزال يتعين عليهم تخصيصهم. عند إجراء تسلسل في حلقة ضيقة، فإن هذا سوف يضع الكثير من الضغط على جامع القمامة، وإذا لم يكن هناك شيء آخر، فسيتم تشغيل التعليمات البرمجية ببطء شديد. لقد رأيت تأثير أداء هذه الأجرة الأولى، ويصبح دراماتيكية حقا حيث تصبح السلسلة المتسلسلة أكبر.

النهج الموصى به هو استخدام دائما StringBuilder إذا كنت تفعل أكثر من بضع سلسلة سلسلة. StringBuilder يستخدم المخزن المؤقت قابل للتغيير لتقليل عدد المخصصات اللازمة في بناء السلسلة الخاصة بك.

تتسلسل سلسلة السلسلة آمنة على الرغم من كثيف الذاكرة أكثر من استخدام Stringbuilder إذا قام بتدوير أعداد كبيرة من السلاسل في حلقة. وفي الحالات القصوى، يمكنك نفاد الذاكرة.

انها بالتأكيد تقريبا خطأ في التعليمات البرمجية الخاصة بك.

ربما كنت تتوقف عن عدد كبير جدا من السلاسل. أو ربما هذا شيء آخر مختلف تماما.

سأعود إلى تصحيح الأخطاء دون أي تصورات مسبقة من السبب الجذري - إذا كنت لا تزال تواجه مشاكل في محاولة تقليلها إلى الحد الأدنى اللازم لإعادة توضيح المشكلة والرمز البريدي.

كم من الوقت سوف يستغرق نسخة التسلسل مقابل إصدار سلسلة منشئ؟ من الممكن إغلاق اتصالك ب DB. إذا كنت تفعل الكثير من التسلسل، فسوف أذهب و / Stringbuilder لأنها أكثر كفاءة بعض الشيء.

قد تكون إحدى السبب هو أن السلاسل غير ثابتة في .NET، لذلك عندما تقوم بعملية على واحدة مثل التزليل، فأنت تقوم بالفعل بإنشاء سلسلة جديدة.

سبب محتمل آخر هو أن طول السلسلة هو int، لذلك الحد الأقصى للطول الممكن هو Int32.maxvalue أو 2،147،483،647.

في أي حال، يكون Stringbuilder أفضل من "String1 + String2" لهذا النوع من التشغيل. على الرغم من أن استخدام إمكانات XML المضمنة سيكون أفضل.

string.Concat(string[]) هي إلى حد بعيد أسرع طريقة لسلاسل السلاسل. انها تقتل القمامة StringBuilder في الأداء عند استخدامها في الحلقات، خاصة إذا قمت بإنشاء StringBuilder في كل تكرار. هناك الكثير من المراجع إذا كنت تنسيق جوجل "C # سلسلة vs Stringbuilder" أو شيء من هذا القبيل.http://www.codeproject.com/kb/cs/stringbuilder_vs_string.aspx. يمنحك أيسر عن الأوقات. هنا String.join يفوز باختبار التسليط ولكني أؤدي هذا لأن string.Concat(string, string) يستخدم بدلا من الإصدار الزائد الذي يأخذ صفيف. إذا ألقي نظرة على رمز MSIL الذي يتم إنشاؤه بواسطة الطرق المختلفة، فسترى ما يحدث تحت غطاء محرك السيارة.

ها هي رصاصة في الظلام ...

الأوتار في .NET (وليس Stringbuilders) تذهب إلى سلسلة متدرب سلسلة. هذا هو أساسا منطقة تديرها CLR لمشاركة السلاسل لتحسين الأداء. يجب أن يكون هناك حد ما هنا، على الرغم من أنني ليس لدي أي فكرة عما هذا الحد. أتصور كل التسليط الذي تقوم به هو ضرب سقف بركة متدرب سلسلة. لذلك تقول SQL نعم لدي قيمة لك، لكن لا يمكن أن تضعه في أي مكان حتى تحصل على استثناء.

اختبار سريع وسهل سيكون ngen. تجميعك ومعرفة ما إذا كنت لا تزال تحصل على الخطأ. بعد ngen'ing، لم يعد التطبيق سوف تستخدم حمام السباحة.

إذا فشل ذلك، سأتصل ب Microsoft بمحاولة الحصول على بعض التفاصيل الثابتة. أعتقد أن فكرتي تبدو معقولة، لكن ليس لدي أي فكرة عن سبب عملها في وضع التصحيح. ربما في صراخ وضع التصحيح ليست متتالية. أنا أيضا لا خبير.

عند ضبط السلاسل معا، أستخدم دائما StringBuilder. انها مصممة لذلك وهي أكثر كفاءة تستخدم ببساطة "string1 + string2".

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top