หรือตอนนี้เป็นวิธีอื่น ๆ ?
จากสิ่งที่ฉันได้ยินมีบางพื้นที่ที่ C # พิสูจน์ได้ว่าเร็วกว่า C ++ แต่ฉันไม่เคยกล้าพอที่จะทดสอบด้วยตัวเอง
คิดว่าคุณคนใดสามารถอธิบายความแตกต่างในรายละเอียดเหล่านี้หรือชี้ให้ฉันถูกที่สำหรับข้อมูลนี้
หรือตอนนี้เป็นวิธีอื่น ๆ ?
จากสิ่งที่ฉันได้ยินมีบางพื้นที่ที่ C # พิสูจน์ได้ว่าเร็วกว่า C ++ แต่ฉันไม่เคยกล้าพอที่จะทดสอบด้วยตัวเอง
คิดว่าคุณคนใดสามารถอธิบายความแตกต่างในรายละเอียดเหล่านี้หรือชี้ให้ฉันถูกที่สำหรับข้อมูลนี้
คำตอบ:
ไม่มีเหตุผลที่แน่ชัดว่าทำไมภาษาที่ใช้ bytecode เช่น C # หรือ Java ที่มี JIT ไม่สามารถเร็วเท่ากับรหัส C ++ อย่างไรก็ตามรหัส C ++ ที่ใช้จะเร็วขึ้นอย่างมีนัยสำคัญเป็นเวลานานและในวันนี้ยังคงมีอยู่ในหลายกรณี นี่เป็นสาเหตุหลักมาจากการเพิ่มประสิทธิภาพของ JIT ขั้นสูงที่ซับซ้อนในการใช้งานและสิ่งที่เจ๋งจริงๆกำลังมาถึงตอนนี้เท่านั้น
ดังนั้น C ++ จึงเร็วกว่าในหลายกรณี แต่นี่เป็นเพียงส่วนหนึ่งของคำตอบ กรณีที่ C ++ เร็วกว่าจริง ๆ แล้วเป็นโปรแกรมที่ได้รับการปรับให้เหมาะสมอย่างสูงโดยที่โปรแกรมเมอร์ผู้เชี่ยวชาญได้ทำการปรับปรุงโค้ดให้ดีที่สุด สิ่งนี้ไม่เพียงเสียเวลามาก (และมีราคาแพง) แต่ยังนำไปสู่ข้อผิดพลาดเนื่องจากการเพิ่มประสิทธิภาพมากเกินไป
ในทางกลับกันโค้ดในภาษาที่แปลจะเร็วขึ้นในรันไทม์รุ่นใหม่กว่า (.NET CLR หรือ Java VM) โดยที่คุณไม่ต้องทำอะไรเลย และมีการเพิ่มประสิทธิภาพที่มีประโยชน์มากมายคอมไพเลอร์ JIT สามารถทำสิ่งนั้นไม่ได้ในภาษาที่มีพอยน์เตอร์ นอกจากนี้บางคนโต้แย้งว่าการรวบรวมขยะโดยทั่วไปควรจะรวดเร็วหรือเร็วกว่าการจัดการหน่วยความจำด้วยตนเองและในหลายกรณีก็เป็นเช่นนั้น โดยทั่วไปคุณสามารถนำไปใช้และบรรลุผลทั้งหมดนี้ใน C ++ หรือ C แต่มันจะซับซ้อนและมีข้อผิดพลาดมากขึ้น
ดังที่ Donald Knuth กล่าวว่า "การเพิ่มประสิทธิภาพก่อนวัยอันควรเป็นรากฐานของความชั่วร้ายทั้งหมด" หากคุณทราบแน่ชัดว่าแอปพลิเคชันของคุณส่วนใหญ่จะประกอบด้วยเลขคณิตสำคัญที่มีประสิทธิภาพสูงและเป็นคอขวดและแน่นอนว่าจะเร็วกว่าใน C ++ และคุณมั่นใจว่า C ++ จะไม่ขัดแย้งกับผู้อื่นของคุณ ข้อกำหนดไปสำหรับ C ++ ในอีกกรณีหนึ่งให้จดจ่อกับการใช้งานแอปพลิเคชันของคุณอย่างถูกต้องในภาษาที่เหมาะสมกับคุณที่สุดแล้วค้นหาคอขวดของประสิทธิภาพถ้ามันทำงานช้าเกินไป ในกรณีที่เลวร้ายที่สุดคุณอาจต้องโทรออกไปยังรหัส C ผ่านอินเทอร์เฟซฟังก์ชั่นต่างประเทศดังนั้นคุณจะยังคงมีความสามารถในการเขียนส่วนที่สำคัญในภาษาระดับต่ำกว่า
โปรดทราบว่ามันค่อนข้างง่ายในการเพิ่มประสิทธิภาพโปรแกรมที่ถูกต้อง แต่ยากมากที่จะแก้ไขโปรแกรมที่ได้รับการปรับปรุงให้ดีที่สุด
การให้เปอร์เซ็นต์ความได้เปรียบความเร็วที่แท้จริงนั้นเป็นไปไม่ได้มันขึ้นอยู่กับโค้ดของคุณเป็นส่วนใหญ่ ในหลายกรณีการใช้ภาษาโปรแกรมไม่ได้เป็นปัญหาคอขวด ใช้เบนช์มาร์กที่http://benchmarksgame.alioth.debian.org/ด้วยความสงสัยอย่างมากเนื่องจากการทดสอบเลขคณิตเหล่านี้ส่วนใหญ่ซึ่งไม่น่าจะคล้ายกับรหัสของคุณเลย
C # อาจไม่เร็วกว่านี้ แต่จะทำให้คุณ / ฉันเร็วขึ้น นั่นเป็นมาตรการที่สำคัญที่สุดสำหรับสิ่งที่ฉันทำ :)
เร็วกว่าห้าส้ม หรือมากกว่า: อาจไม่มีคำตอบแบบครอบคลุม (ถูกต้อง) C ++ เป็นภาษาที่คอมไพล์ด้วยสแตติก มีความแตกต่างมากมายที่คำถามเช่น“ ไม่เร็วเท่าไหร่” ไม่สามารถตอบได้แม้แต่โดยสั่งการให้มีขนาด
ฉันจะเริ่มต้นด้วยการไม่เห็นด้วยกับส่วนหนึ่งของคำตอบที่ยอมรับ (และมีชื่อเสียงดี) สำหรับคำถามนี้โดยระบุว่า:
มีเหตุผลมากมายที่รหัส JITted จะทำงานช้ากว่าโปรแกรม C ++ ที่เหมาะสมที่สุด (หรือภาษาอื่น ๆ ที่ไม่มีค่าใช้จ่ายรันไทม์)รวมถึง:
คำนวณรอบที่ใช้กับรหัส JIT ที่รันไทม์โดยคำจำกัดความไม่พร้อมใช้งานสำหรับใช้ในการดำเนินการโปรแกรม
พา ธ ร้อน ๆ ใน JITter จะแข่งขันกับโค้ดของคุณสำหรับคำสั่งและแคชข้อมูลใน CPU เรารู้ว่าแคชนั้นมีอิทธิพลต่อประสิทธิภาพและภาษาดั้งเดิมอย่าง C ++ ไม่มีการโต้แย้งประเภทนี้ตามนิยาม
งบประมาณเวลาของเครื่องมือเพิ่มประสิทธิภาพเวลาทำงานจำเป็นต้องมีข้อ จำกัด มากกว่าของเครื่องมือเพิ่มประสิทธิภาพขณะรวบรวม (ดังที่ผู้วิจารณ์คนอื่นชี้ให้เห็น)
บรรทัดด้านล่าง: ในที่สุดคุณจะเกือบแน่นอนจะสามารถสร้างการดำเนินงานได้เร็วขึ้นใน C ++ กว่าที่คุณสามารถทำได้ใน C #
ตอนนี้จากที่กล่าวไปแล้วว่าปริมาณที่เร็วขึ้นจริง ๆ ไม่สามารถคำนวณได้เนื่องจากมีตัวแปรมากเกินไป: งานโดเมนปัญหาฮาร์ดแวร์คุณภาพของการใช้งานและปัจจัยอื่น ๆ คุณจะต้องทำการทดสอบในสถานการณ์ของคุณเพื่อกำหนดความแตกต่างในประสิทธิภาพแล้วตัดสินใจว่ามันคุ้มค่ากับความพยายามและความซับซ้อนเพิ่มเติมหรือไม่
นี่เป็นหัวข้อที่ซับซ้อนและยาวมาก แต่ฉันรู้สึกว่ามันคุ้มค่าที่จะกล่าวถึงเพื่อความสมบูรณ์ที่ C # ของ runtime optimizer นั้นยอดเยี่ยมและสามารถทำการปรับแต่งแบบไดนามิกบางอย่างที่ runtime ที่ C ++ ไม่สามารถรวบรวมได้ ( เครื่องมือเพิ่มประสิทธิภาพคงที่) ถึงแม้จะมีข้อได้เปรียบโดยทั่วไปแล้วก็ยังคงลึกอยู่ในศาลของแอปพลิเคชันเนทีฟ แต่เครื่องมือเพิ่มประสิทธิภาพแบบไดนามิกเป็นเหตุผลสำหรับตัวระบุ " เกือบจะแน่นอน" ที่ระบุข้างต้น
-
ในแง่ของประสิทธิภาพการทำงานที่เกี่ยวข้องฉันยังถูกรบกวนด้วยตัวเลขและการสนทนาที่ฉันเห็นในคำตอบอื่น ๆ ดังนั้นฉันคิดว่าฉันจะพูดสอดในและในเวลาเดียวกันให้การสนับสนุนบางอย่างสำหรับงบที่ฉันได้ทำไป
ส่วนใหญ่ของปัญหาเกี่ยวกับการวัดประสิทธิภาพเหล่านี้คือคุณไม่สามารถเขียนรหัส C ++ ราวกับว่าคุณกำลังเขียน C # และคาดหวังว่าจะได้ผลลัพธ์ที่เป็นตัวแทน (เช่นการดำเนินการจัดสรรหน่วยความจำหลายพันรายการใน C ++ จะทำให้คุณแย่มาก
แต่ฉันเขียนรหัส C ++ ที่เป็นสำนวนมากกว่าเล็กน้อยและเปรียบเทียบกับรหัส C # @Wiory ที่ให้ไว้ การเปลี่ยนแปลงสำคัญสองประการที่ฉันทำกับรหัส C ++ คือ:
1) vector ใช้ :: Reserve ()
2) ทำให้อาร์เรย์ 2d แบนเป็น 1d เพื่อให้ได้ตำแหน่งแคชที่ดีขึ้น (บล็อกต่อเนื่อง)
C # (.NET 4.6.1)
private static void TestArray()
{
const int rows = 5000;
const int columns = 9000;
DateTime t1 = System.DateTime.Now;
double[][] arr = new double[rows][];
for (int i = 0; i < rows; i++)
arr[i] = new double[columns];
DateTime t2 = System.DateTime.Now;
Console.WriteLine(t2 - t1);
t1 = System.DateTime.Now;
for (int i = 0; i < rows; i++)
for (int j = 0; j < columns; j++)
arr[i][j] = i;
t2 = System.DateTime.Now;
Console.WriteLine(t2 - t1);
}
เวลาทำงาน (Release): เริ่ม: 124ms, Fill: 165ms
C ++ 14 (เสียงดังกราว v3.8 / C2)
#include <iostream>
#include <vector>
auto TestSuite::ColMajorArray()
{
constexpr size_t ROWS = 5000;
constexpr size_t COLS = 9000;
auto initStart = std::chrono::steady_clock::now();
auto arr = std::vector<double>();
arr.reserve(ROWS * COLS);
auto initFinish = std::chrono::steady_clock::now();
auto initTime = std::chrono::duration_cast<std::chrono::microseconds>(initFinish - initStart);
auto fillStart = std::chrono::steady_clock::now();
for(auto i = 0, r = 0; r < ROWS; ++r)
{
for (auto c = 0; c < COLS; ++c)
{
arr[i++] = static_cast<double>(r * c);
}
}
auto fillFinish = std::chrono::steady_clock::now();
auto fillTime = std::chrono::duration_cast<std::chrono::milliseconds>(fillFinish - fillStart);
return std::make_pair(initTime, fillTime);
}
เวลาทำงาน (เผยแพร่): เริ่ม: 398µs (ใช่นั่นคือไมโครวินาที) เติม: 152ms
ข้อสังเกต
การเปลี่ยนการใช้ C # ไปเป็นการใช้งานอาร์เรย์ 1d เดียวกันให้ผลเริ่มต้น: 40ms, เติม: 171ms, รวม: 211ms ( C ++ ยังเร็วกว่าเกือบ 40% )
มันยากกว่ามากในการออกแบบและเขียนรหัส "เร็ว" ใน C ++ กว่าจะเขียนรหัส "ปกติ" ในภาษาใดภาษาหนึ่ง
มันเป็นเรื่องง่ายที่จะได้รับประสิทธิภาพที่ต่ำใน C ++ เราเห็นว่าด้วยประสิทธิภาพเวกเตอร์ที่ไม่ได้จอง และมีข้อผิดพลาดมากมายเช่นนี้
ประสิทธิภาพของ C # นั้นค่อนข้างน่าทึ่งเมื่อคุณพิจารณาทุกอย่างที่เกิดขึ้นขณะใช้งานจริง และประสิทธิภาพนั้นค่อนข้างง่ายต่อการเข้าถึง
ข้อมูลเพิ่มเติมเกี่ยวกับการเปรียบเทียบประสิทธิภาพของ C ++ และ C #: https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=gpp&lang2=csharpcore
บรรทัดล่างคือ C ++ ให้คุณควบคุมประสิทธิภาพได้มากขึ้น คุณต้องการใช้ตัวชี้หรือไม่? อ้างอิง? หน่วยความจำสแต็ค? กอง? ความแตกต่างแบบไดนามิกหรือกำจัดค่าใช้จ่ายรันไทม์ของ vtable ด้วยความหลากหลายแบบคงที่ (ผ่านแม่แบบ / CRTP)? ใน C ++ คุณต้อง ... เอ้อจะได้รับการให้ทางเลือกเหล่านี้ทั้งหมด (และอื่น ๆ ) ตัวเองนึกคิดเพื่อให้การแก้ปัญหาที่อยู่ดีที่สุดของคุณปัญหาที่คุณกำลังแก้ปัญหา
ถามตัวเองว่าคุณต้องการหรือต้องการการควบคุมนั้นจริง ๆ หรือเปล่าเพราะถึงแม้จะเป็นเพียงตัวอย่างเล็กน้อยคุณสามารถเห็นได้ว่าแม้จะมีการปรับปรุงประสิทธิภาพที่สำคัญ แต่ก็ต้องใช้การลงทุนที่ลึกกว่า
int[,]
... ติดตามตัวอย่าง
จากประสบการณ์ของฉัน (และฉันทำงานกับทั้งสองภาษามาก) ปัญหาหลักของ C # เมื่อเทียบกับ C ++ คือการใช้หน่วยความจำสูงและฉันไม่พบวิธีที่ดีในการควบคุม มันเป็นการใช้หน่วยความจำที่ในที่สุดจะชะลอตัวลงซอฟต์แวร์. NET
ปัจจัยอีกประการหนึ่งคือคอมไพเลอร์ JIT ไม่สามารถมีเวลามากเกินไปในการปรับแต่งขั้นสูงเนื่องจากมันทำงานที่รันไทม์และผู้ใช้จะสังเกตเห็นว่าใช้เวลานานเกินไป ในอีกทางหนึ่งคอมไพเลอร์ C ++ มีเวลาทั้งหมดที่ต้องทำการปรับแต่งที่รวบรวมเวลา ปัจจัยนี้สำคัญน้อยกว่าการใช้หน่วยความจำ IMHO
สถานการณ์หนึ่งโดยเฉพาะที่ C ++ ยังคงมีระดับสูงกว่า (และจะเป็นเวลาหลายปีที่จะมาถึง) เกิดขึ้นเมื่อการตัดสินใจ polymorphic สามารถกำหนดไว้ล่วงหน้าได้ในเวลารวบรวม
โดยทั่วไปการห่อหุ้มและการตัดสินใจรอการตัดบัญชีเป็นสิ่งที่ดีเพราะจะทำให้โค้ดมีความยืดหยุ่นมากขึ้นง่ายต่อการปรับให้เข้ากับความต้องการที่เปลี่ยนแปลงและง่ายต่อการใช้เป็นกรอบงาน นี่คือเหตุผลที่การเขียนโปรแกรมเชิงวัตถุใน C # มีประสิทธิผลมากและสามารถวางนัยภายใต้คำว่า "การวางนัยทั่วไป" น่าเสียดายที่ลักษณะทั่วไปแบบนี้มาจากต้นทุนในการใช้งาน
โดยทั่วไปค่าใช้จ่ายนี้จะไม่สำคัญ แต่มีแอปพลิเคชันที่ค่าใช้จ่ายในการเรียกวิธีการเสมือนและการสร้างวัตถุสามารถสร้างความแตกต่าง (โดยเฉพาะอย่างยิ่งเนื่องจากวิธีการเสมือนป้องกันการเพิ่มประสิทธิภาพอื่น ๆ นี่คือที่ C ++ มีข้อได้เปรียบอย่างมากเนื่องจากคุณสามารถใช้เทมเพลตเพื่อให้ได้ลักษณะทั่วไปที่แตกต่างกันซึ่งไม่มีผลกระทบกับรันไทม์ แต่ไม่จำเป็นต้องมี polymorphic น้อยกว่า OOP ในความเป็นจริงกลไกทั้งหมดที่ประกอบเป็น OOP สามารถสร้างแบบจำลองได้โดยใช้เทคนิคเทมเพลตเท่านั้นและการแก้ปัญหาเวลาคอมไพล์
ในกรณีดังกล่าว (และเป็นที่ยอมรับมักจะถูก จำกัด อยู่ในโดเมนปัญหาพิเศษ), C ++ ชนะเทียบกับ C # และภาษาที่เทียบเท่ากัน
sort(arr, generic_comparer)
จะมีประสิทธิภาพเท่ากับลูปที่เขียนด้วยมือใน C ++ มันจะไม่อยู่ใน C #
C ++ (หรือ C สำหรับเรื่องนั้น) ให้คุณควบคุมโครงสร้างข้อมูลของคุณอย่างละเอียด หากคุณต้องการ bit-twiddle คุณมีตัวเลือกนั้น แอป Java หรือ. NET ขนาดใหญ่ที่ได้รับการจัดการ (OWB, Visual Studio 2005 ) ที่ใช้โครงสร้างข้อมูลภายในของไลบรารี Java / .NET มีกระเป๋าสัมภาระติดตัว ฉันได้เห็นเซสชันนักออกแบบ OWB ที่ใช้ RAM และ BIDS มากกว่า 400 MB สำหรับการออกแบบคิวบ์หรือETLเข้าสู่ 100 MB ด้วยเช่นกัน
บนเวิร์กโหลดที่คาดการณ์ได้ (เช่นการวัดประสิทธิภาพส่วนใหญ่ที่ทำซ้ำกระบวนการหลายครั้ง) JIT สามารถรับโค้ดที่ได้รับการปรับให้เหมาะสมที่สุดพอที่จะไม่มีความแตกต่างในทางปฏิบัติ
IMO บนแอปพลิเคชันขนาดใหญ่ความแตกต่างนั้นไม่มากนัก JIT เนื่องจากโครงสร้างข้อมูลที่ใช้งานโค้ดอยู่ ในกรณีที่แอปพลิเคชันหนักหน่วงคุณจะได้รับการใช้แคชที่มีประสิทธิภาพน้อย Cache ที่ผิดพลาดกับซีพียูสมัยใหม่นั้นค่อนข้างแพง ตำแหน่งที่ C หรือ C ++ ชนะได้จริงคือคุณสามารถปรับการใช้โครงสร้างข้อมูลให้เหมาะสมเพื่อเล่นกับแคชแคช
สำหรับกราฟิกคลาส C # Graphics มาตรฐานจะช้ากว่า GDI ที่เข้าถึงผ่านทาง C / C ++ ฉันรู้ว่านี่ไม่มีส่วนเกี่ยวข้องกับภาษาต่อสิ่งอื่น ๆ อีกมากมายด้วยแพลตฟอร์ม. NET ทั้งหมด แต่กราฟิกเป็นสิ่งที่เสนอให้กับนักพัฒนาเพื่อทดแทน GDI และประสิทธิภาพการทำงานของมันแย่มากฉันไม่กล้าแม้แต่จะทำกราฟิก กับมัน
เรามีเกณฑ์มาตรฐานอย่างง่ายที่เราใช้เพื่อดูว่าไลบรารีกราฟิกเร็วแค่ไหนและนั่นเป็นเพียงการวาดเส้นสุ่มในหน้าต่าง C ++ / GDI ยังคงเร็วกับ 10,000 บรรทัดในขณะที่ C # / กราฟิกมีปัญหาในการทำ 1,000 ในเวลาจริง
การรวบรวมขยะเป็นเหตุผลหลักที่ทำให้ Java # CANNOT ไม่สามารถใช้กับระบบเรียลไทม์
GC จะเกิดขึ้นเมื่อใด
มันจะใช้เวลานานเท่าไหร่?
นี่คือไม่ได้กำหนด
เราต้องพิจารณาว่า C # นั้นเทียบได้กับ C ++ ในการทำงานหรือไม่และฉันเขียนโปรแกรมทดสอบบางรายการสำหรับเรื่องนั้น (โดยใช้ Visual Studio 2005 สำหรับทั้งสองภาษา) มันกลับกลายเป็นว่าไม่มีการรวบรวมขยะและพิจารณาเฉพาะภาษา (ไม่ใช่กรอบ) C # มีประสิทธิภาพการทำงานเช่นเดียวกับ C ++ การจัดสรรหน่วยความจำเป็นวิธีที่เร็วกว่าใน C # กว่าใน C ++ และ C # มีขอบเขตเล็กน้อยในการกำหนดเมื่อขนาดข้อมูลเพิ่มขึ้นเกินขอบเขตของแคชบรรทัด อย่างไรก็ตามทั้งหมดนี้ต้องจ่ายให้ในที่สุดและมีค่าใช้จ่ายจำนวนมากในรูปแบบของประสิทธิภาพการทำงานที่ไม่ได้กำหนดไว้สำหรับ C # เนื่องจากการรวบรวมขยะ
ตามปกติมันขึ้นอยู่กับแอปพลิเคชัน มีหลายกรณีที่ C # อาจช้ากว่าและกรณีอื่น ๆ ที่ C ++ เร็วกว่า 5 หรือ 10 เท่าโดยเฉพาะอย่างยิ่งในกรณีที่การดำเนินการสามารถ SIMD ได้ง่าย
ฉันรู้ว่าไม่ใช่สิ่งที่คุณขอ แต่ C # มักจะเขียนได้เร็วกว่า C ++ ซึ่งเป็นโบนัสใหญ่ในเชิงพาณิชย์
C / C ++ สามารถทำงานได้ดีขึ้นอย่างมากในโปรแกรมที่มีทั้งอาร์เรย์ขนาดใหญ่หรือวนลูปหนัก / การวนซ้ำข้ามอาร์เรย์ (ทุกขนาด) นี่คือเหตุผลที่โดยทั่วไปกราฟิกจะเร็วกว่ามากใน C / C ++ เนื่องจากการทำงานของอาเรย์อย่างหนักนั้นรองรับการใช้งานกราฟิกเกือบทั้งหมด .NET นั้นช้าในการดำเนินการทำดัชนีอาเรย์เนื่องจากการตรวจสอบความปลอดภัยทั้งหมดและนี่เป็นจริงโดยเฉพาะอย่างยิ่งสำหรับอาเรย์หลายมิติ (และใช่ใช่อาร์เรย์ C # ที่เป็นรูปสี่เหลี่ยมผืนผ้านั้นช้ากว่าแบบ Jagged แบบอาเรย์)
โบนัสของ C / C ++ เด่นชัดมากที่สุดถ้าคุณติดโดยตรงกับพอยน์เตอร์และหลีกเลี่ยง Boost std::vector
และคอนเทนเนอร์ระดับสูงอื่น ๆ รวมถึงinline
ฟังก์ชั่นเล็ก ๆ ใช้อาร์เรย์โรงเรียนเก่าเมื่อใดก็ตามที่เป็นไปได้ ใช่คุณจะต้องมีบรรทัดของรหัสมากขึ้นเพื่อทำสิ่งเดียวกันกับที่คุณทำใน Java หรือ C # เนื่องจากคุณหลีกเลี่ยงคอนเทนเนอร์ระดับสูง หากคุณต้องการอาร์เรย์ที่มีขนาดแบบไดนามิกคุณจะต้องจำไว้ว่าให้จับคู่new T[]
กับdelete[]
คำสั่งที่เกี่ยวข้อง(หรือใช้std::unique_ptr
) - ราคาสำหรับความเร็วพิเศษคือคุณต้องเขียนโค้ดให้ละเอียดมากขึ้น แต่ในการแลกเปลี่ยนคุณจะกำจัดโอเวอร์เฮดของตัวจัดการหน่วยความจำ / ขยะที่มีการจัดการซึ่งอาจเป็น 20% หรือมากกว่าของเวลาดำเนินการของโปรแกรมเชิงวัตถุอย่างหนักทั้งใน Java และ. NET รวมถึงระบบจัดการขนาดใหญ่ ต้นทุนการทำดัชนีอาร์เรย์ของหน่วยความจำ แอพ C ++ ยังสามารถได้รับประโยชน์จากสวิตช์คอมไพเลอร์ที่ดีในบางกรณี
ฉันเป็นโปรแกรมเมอร์ผู้เชี่ยวชาญใน C, C ++, Java และ C # ฉันเพิ่งมีโอกาสน้อยที่จะใช้โปรแกรมอัลกอริทึมเดียวกันใน 3 ภาษาหลัง โปรแกรมมีการดำเนินการทางคณิตศาสตร์และอาเรย์หลายมิติจำนวนมาก ฉันปรับให้เหมาะสมอย่างมากใน 3 ภาษานี้ ผลลัพธ์เป็นแบบอย่างของสิ่งที่ฉันเห็นโดยทั่วไปในการเปรียบเทียบที่เข้มงวดน้อยกว่า: Java เร็วกว่า C # ประมาณ 1.3 เท่า (JVM ส่วนใหญ่มีการปรับให้เหมาะสมกว่า CLR) และรุ่น C ++ raw pointer มาเร็วกว่า 2.1 เท่า โปรดทราบว่าโปรแกรม C # ใช้รหัสที่ปลอดภัยเท่านั้นซึ่งเป็นความเห็นของฉันที่คุณอาจใช้รหัสใน C ++ ก่อนที่จะใช้unsafe
คำหลัก
เกรงว่าทุกคนจะคิดว่าฉันมีอะไรบางอย่างกับ C # ฉันจะปิดโดยพูดว่า C # น่าจะเป็นภาษาที่ฉันชอบ มันเป็นภาษาที่ใช้ในการพัฒนาอย่างมีเหตุผลใช้งานง่ายและรวดเร็วที่สุดเท่าที่ฉันเคยพบมา ฉันทำต้นแบบของฉันทั้งหมดใน C # ภาษา C # มีข้อได้เปรียบเล็ก ๆ น้อย ๆ ที่เหนือกว่า Java (ใช่ฉันรู้ว่า Microsoft มีโอกาสที่จะแก้ไขข้อบกพร่องของ Java จำนวนมากโดยการเข้าเกมช้าและคัดลอก Java) ดื่มอวยพรให้กับCalendar
ชั้นเรียนของ Java หรือไม่? หาก Microsoft ใช้ความพยายามอย่างแท้จริงในการปรับแต่ง CLR และ. NET JITter ให้ดีที่สุด C # ก็อาจเข้าควบคุมอย่างจริงจัง ฉันประหลาดใจอย่างแท้จริงที่พวกเขายังไม่ได้ทำ - พวกเขาทำหลายสิ่งหลายอย่างในภาษา C # ทำไมไม่ติดตามด้วยการเพิ่มประสิทธิภาพคอมไพเลอร์ที่หนักหน่วง? บางทีถ้าเราทุกคนร้องขอ
new T[]
กับdelete[]
" - คุณไม่ต้อง นอกจากstd::unique_ptr
จะทำเพื่อคุณ
> จากสิ่งที่ฉันได้ยิน ...
ความยากลำบากของคุณดูเหมือนจะเป็นการตัดสินใจว่าสิ่งที่คุณได้ยินมีความน่าเชื่อถือหรือไม่และความยากลำบากนั้นจะเกิดขึ้นซ้ำเมื่อคุณพยายามประเมินการตอบกลับในเว็บไซต์นี้
คุณจะตัดสินใจอย่างไรว่าสิ่งที่คนพูดที่นี่น่าเชื่อถือมากหรือน้อยกว่าที่คุณเคยได้ยินมาก่อน
วิธีการหนึ่งที่จะขอหลักฐาน
เมื่อมีคนอ้างว่า "มีบางพื้นที่ที่ C # พิสูจน์ให้เร็วกว่า C ++" ถามพวกเขาว่าทำไมพวกเขาถึงพูดแบบนั้นขอให้พวกเขาแสดงการวัดขอให้พวกเขาแสดงโปรแกรม บางครั้งพวกเขาก็ทำผิด บางครั้งคุณจะพบว่าพวกเขาเพียงแค่แสดงความคิดเห็นแทนที่จะแบ่งปันบางสิ่งที่พวกเขาสามารถแสดงให้เห็นว่าเป็นเรื่องจริง
บ่อยครั้งที่ข้อมูลและความคิดเห็นจะปะปนกับสิ่งที่ผู้คนเรียกร้องและคุณจะต้องลองและแยกแยะว่าอันไหน ตัวอย่างเช่นจากคำตอบในฟอรั่มนี้:
"ใช้มาตรฐานที่http://shootout.alioth.debian.org/ ด้วยความสงสัยอย่างมากเนื่องจากการทดสอบเลขคณิตเหล่านี้ส่วนใหญ่ซึ่งน่าจะไม่คล้ายกับรหัสของคุณเลย"
ถามตัวเองว่าคุณเข้าใจจริง ๆ ว่า"รหัสทดสอบเลขคณิตส่วนใหญ่"หมายถึงอะไรแล้วถามตัวคุณเองว่าผู้เขียนแสดงให้คุณเห็นจริงหรือไม่ว่าการอ้างสิทธิ์ของเขานั้นเป็นความจริง
"นั่นเป็นการทดสอบที่ไร้ประโยชน์เนื่องจากมันขึ้นอยู่กับว่าแต่ละโปรแกรมได้รับการปรับให้เหมาะสมหรือไม่ฉันได้พยายามเพิ่มความเร็วให้กับโปรแกรมบางโปรแกรม 4-6 เท่าหรือมากกว่าทำให้ชัดเจนว่าการเปรียบเทียบระหว่างโปรแกรมที่ไม่ได้เพิ่มประสิทธิภาพนั้นค่อนข้างดี โง่."
ถามตัวคุณเองว่าผู้แต่งแสดงให้คุณเห็นหรือไม่ว่าเขาสามารถ "เร่งบางอย่างได้ 4-6 ครั้งขึ้นไป" - มันเป็นเรื่องง่ายที่จะทำ!
สำหรับปัญหา 'ขนานที่น่าอับอาย' เมื่อใช้ Intel TBB และ OpenMP บน C ++ ฉันพบว่าประสิทธิภาพเพิ่มขึ้นประมาณ 10 เท่าเมื่อเทียบกับปัญหาที่คล้ายกัน (คณิตศาสตร์บริสุทธิ์) ที่ทำด้วย C # และ TPL SIMD เป็นพื้นที่หนึ่งที่ C # ไม่สามารถแข่งขันได้ แต่ฉันก็รู้สึกว่า TPL มีค่าใช้จ่ายที่ใหญ่มาก
ที่กล่าวว่าฉันใช้ C ++ สำหรับงานที่สำคัญต่อประสิทธิภาพซึ่งฉันรู้ว่าฉันจะสามารถมัลติเธรดและรับผลลัพธ์ได้อย่างรวดเร็ว สำหรับทุกอย่างอื่น C # (และบางครั้ง F #) ก็ใช้ได้
มันเป็นคำถามที่คลุมเครืออย่างยิ่งโดยไม่มีคำตอบที่ชัดเจน
ตัวอย่างเช่น; ฉันอยากเล่นเกม 3D ที่สร้างขึ้นใน C ++ มากกว่าใน C # เพราะประสิทธิภาพดีขึ้นกว่าเดิมมาก (และฉันรู้ XNA ฯลฯ แต่มันไม่มีทางใกล้กับของจริง)
ในทางกลับกันตามที่ได้กล่าวไปแล้ว คุณควรพัฒนาในภาษาที่ให้คุณทำสิ่งที่คุณต้องการได้อย่างรวดเร็วและจากนั้นถ้าจำเป็นเพิ่มประสิทธิภาพ
ภาษา NET สามารถเร็วเท่ากับรหัส C ++ หรือเร็วกว่าแต่รหัส C ++ จะมีปริมาณงานคงที่มากขึ้นเนื่องจาก. NET runtime ต้องหยุดชั่วคราวสำหรับGCแม้ว่าจะฉลาดมากเกี่ยวกับการหยุดชั่วคราว
ดังนั้นหากคุณมีรหัสที่ต้องทำงานอย่างรวดเร็วอย่างต่อเนื่องโดยไม่หยุดชั่วคราว. NET จะแนะนำเวลาแฝงในบางจุดแม้ว่าคุณจะระมัดระวังเกี่ยวกับ runtime GC ก็ตาม
ในทางทฤษฎีสำหรับการทำงานยาวพลิเคชันเซิร์ฟเวอร์ชนิดเป็นภาษา JIT รวบรวมจะกลายเป็นมากเร็วกว่าคู่เรียบเรียงโดยกำเนิด เนื่องจากโดยทั่วไปภาษาที่คอมไพล์แล้วของ JIT จะถูกคอมไพล์เป็นภาษาระดับกลางค่อนข้างต่ำคุณสามารถทำการออพติไมซ์ระดับสูงได้ในเวลารวบรวม ข้อได้เปรียบที่สำคัญคือ JIT สามารถทำการคอมไพล์ส่วนของโค้ดซ้ำได้อย่างต่อเนื่องเนื่องจากได้รับข้อมูลมากขึ้นเกี่ยวกับวิธีการใช้แอปพลิเคชัน สามารถจัดเส้นทางรหัสที่พบมากที่สุดเพื่อให้การคาดการณ์ของสาขาประสบความสำเร็จบ่อยที่สุดเท่าที่จะทำได้ สามารถจัดเรียงรหัสบล็อกแยกต่างหากที่มักถูกเรียกเข้าด้วยกันเพื่อเก็บไว้ในแคช มันสามารถใช้ความพยายามมากขึ้นในการเพิ่มประสิทธิภาพลูปภายใน
ฉันสงสัยว่ามันทำโดย. NET หรือของ JREs ใด ๆ แต่มันถูกวิจัยกลับเมื่อฉันอยู่ในมหาวิทยาลัยดังนั้นจึงไม่มีเหตุผลที่จะคิดว่าสิ่งเหล่านี้อาจหาทางสู่โลกแห่งความจริงในไม่ช้า .
แอปพลิเคชันที่ต้องการการเข้าถึงหน่วยความจำอย่างเข้มข้นเช่น การจัดการรูปภาพมักจะดีกว่าเขียนในสภาพแวดล้อมที่ไม่มีการจัดการ (C ++) กว่าที่ได้รับการจัดการ (C #) ลูปด้านในที่ได้รับการปรับให้เหมาะสมด้วยตัวบ่งชี้เลขคณิตนั้นง่ายต่อการควบคุมใน C ++ ใน C # คุณอาจต้องใช้รหัสที่ไม่ปลอดภัยเพื่อให้ได้ประสิทธิภาพใกล้เคียงกัน
ฉันได้ทดสอบvector
ใน C ++ และ C # ที่เทียบเท่า - List
และ 2d arrays ง่ายๆ
ฉันใช้รุ่น Visual Express C # / C ++ 2010 Express ทั้งสองโปรเจ็กต์เป็นแอปพลิเคชั่นคอนโซลที่เรียบง่ายฉันได้ทดสอบพวกมันในโหมดมาตรฐาน (ไม่มีการตั้งค่าแบบกำหนดเอง) และโหมดดีบัก รายการ C # ทำงานได้เร็วขึ้นบนพีซีของฉันการเริ่มต้นอาร์เรย์ก็เร็วขึ้นใน C # การดำเนินการทางคณิตศาสตร์จะช้าลง
ฉันใช้ Intel Core2Duo P8600@2.4GHz, C # - .NET 4.0
ฉันรู้ว่าการใช้เวกเตอร์นั้นแตกต่างจากรายการ C # แต่ฉันแค่ต้องการทดสอบคอลเลกชันที่ฉันจะใช้เพื่อเก็บวัตถุของฉัน (และความสามารถในการใช้ตัวเข้าถึงดัชนี)
แน่นอนคุณต้องล้างหน่วยความจำ (สมมติว่าสำหรับการใช้งานทุกครั้งnew
) แต่ฉันต้องการที่จะทำให้รหัสง่าย
การทดสอบเวกเตอร์ C ++ :
static void TestVector()
{
clock_t start,finish;
start=clock();
vector<vector<double>> myList=vector<vector<double>>();
int i=0;
for( i=0; i<500; i++)
{
myList.push_back(vector<double>());
for(int j=0;j<50000;j++)
myList[i].push_back(j+i);
}
finish=clock();
cout<<(finish-start)<<endl;
cout<<(double(finish - start)/CLOCKS_PER_SEC);
}
การทดสอบรายการ C #:
private static void TestVector()
{
DateTime t1 = System.DateTime.Now;
List<List<double>> myList = new List<List<double>>();
int i = 0;
for (i = 0; i < 500; i++)
{
myList.Add(new List<double>());
for (int j = 0; j < 50000; j++)
myList[i].Add(j *i);
}
DateTime t2 = System.DateTime.Now;
Console.WriteLine(t2 - t1);
}
C ++ - อาร์เรย์:
static void TestArray()
{
cout << "Normal array test:" << endl;
const int rows = 5000;
const int columns = 9000;
clock_t start, finish;
start = clock();
double** arr = new double*[rows];
for (int i = 0; i < rows; i++)
arr[i] = new double[columns];
finish = clock();
cout << (finish - start) << endl;
start = clock();
for (int i = 0; i < rows; i++)
for (int j = 0; j < columns; j++)
arr[i][j] = i * j;
finish = clock();
cout << (finish - start) << endl;
}
C # - อาร์เรย์:
private static void TestArray()
{
const int rows = 5000;
const int columns = 9000;
DateTime t1 = System.DateTime.Now;
double[][] arr = new double[rows][];
for (int i = 0; i < rows; i++)
arr[i] = new double[columns];
DateTime t2 = System.DateTime.Now;
Console.WriteLine(t2 - t1);
t1 = System.DateTime.Now;
for (int i = 0; i < rows; i++)
for (int j = 0; j < columns; j++)
arr[i][j] = i * j;
t2 = System.DateTime.Now;
Console.WriteLine(t2 - t1);
}
เวลา: (การเปิดตัว / การดีบัก)
C ++
(ใช่ 13 วินาทีฉันมักจะมีปัญหากับรายการ / เวกเตอร์ในโหมดแก้ไขข้อบกพร่อง)
ค#:
System.DateTime.Now
แต่เป็นคลาสนาฬิกาจับเวลา
มันขึ้นอยู่กับ ถ้ารหัสไบต์ถูกแปลเป็นรหัสเครื่อง (และไม่ใช่แค่ JIT) (ฉันหมายถึงถ้าคุณรันโปรแกรม) และถ้าโปรแกรมของคุณใช้การจัดสรร / การจัดสรรคืนจำนวนมากมันอาจเร็วกว่าเพราะอัลกอริทึมGCต้องการเพียงหนึ่งรอบ (ในทางทฤษฎี) ผ่านหน่วยความจำทั้งหมดหนึ่งครั้ง แต่การเรียกใช้ malloc / realloc / free C / C ++ ปกติทำให้เกิดโอเวอร์เฮดสำหรับการโทรทุกครั้ง (การโทรโอเวอร์เฮดโอเวอร์เฮดโครงสร้างข้อมูล
ดังนั้นจึงเป็นไปได้ในทางทฤษฎี (สำหรับภาษา GC อื่น ๆ ด้วย)
ฉันไม่เห็นข้อเสียอย่างที่สุดที่จะไม่สามารถใช้metaprogrammingกับ C # สำหรับแอปพลิเคชันส่วนใหญ่ได้เนื่องจากโปรแกรมเมอร์ส่วนใหญ่ไม่ได้ใช้งาน
ข้อได้เปรียบที่สำคัญอีกอย่างหนึ่งคือ SQL เช่นLINQ "extension" ให้โอกาสแก่ผู้รวบรวมเพื่อเพิ่มประสิทธิภาพการโทรไปยังฐานข้อมูล (กล่าวอีกนัยหนึ่งผู้แปลสามารถรวบรวม LINQ ทั้งหมดเป็นหนึ่งใน "blob" ไบนารีโดยที่ฟังก์ชันที่ถูกเรียก สำหรับการใช้งานของคุณได้รับการปรับปรุง แต่ฉันคาดเดาที่นี่)
ฉันคิดว่ามีแอปพลิเคชันที่เขียนใน C # ทำงานเร็วและมีแอปเขียน C ++ ที่ทำงานเร็วกว่าเดิม (เช่น C ++ เก่ากว่า ... และใช้ UNIX ด้วย ... )
- คำถามคือ - ผู้ใช้คืออะไร และนักพัฒนาบ่นเกี่ยวกับ ... เอา
ล่ะ IMHO ในกรณีของ C # เรามี UI ที่สะดวกสบายเป็นอย่างดีลำดับชั้นของไลบรารีที่ดีมากและระบบอินเตอร์เฟสทั้งหมดของ CLI ในกรณีของ C ++ เรามีเทมเพลต, ATL, COM, MFC และ Shebang ทั้งหมดของ alreadyc ที่เขียนและเรียกใช้โค้ดเช่น OpenGL, DirectX และอื่น ๆ ... นักพัฒนาบ่นว่าการเรียก GC เพิ่มขึ้นอย่างไม่ จำกัด ในกรณีของ C # (หมายถึงโปรแกรมทำงานรวดเร็ว ในหนึ่งวินาที - ปัง! มันติดอยู่)
ในการเขียนโค้ดใน C # นั้นง่ายและรวดเร็ว (อย่าลืมว่ายังเพิ่มโอกาสในการเกิดข้อผิดพลาดในกรณีของ C ++ ผู้พัฒนาบ่นว่าหน่วยความจำรั่ว - หมายถึงทับเรียกระหว่าง DLLs และ DLL DLL - ปัญหากับ การสนับสนุนและการเปลี่ยนไลบรารี่ใหม่โดย ...
ฉันคิดว่าทักษะที่คุณมีในภาษาการเขียนโปรแกรมยิ่งคุณภาพ (และความเร็ว) มากขึ้นจะทำให้ซอฟต์แวร์ของคุณมีลักษณะเฉพาะ
ฉันจะใช้วิธีนี้: โปรแกรมเมอร์ที่เขียนโค้ดได้เร็วขึ้นเป็นคนที่รู้มากขึ้นเกี่ยวกับสิ่งที่ทำให้เครื่องปัจจุบันก้าวไปอย่างรวดเร็วและบังเอิญพวกเขายังเป็นคนที่ใช้เครื่องมือที่เหมาะสมที่ช่วยให้ระดับต่ำแม่นยำและกำหนดขึ้น เทคนิคการปรับให้เหมาะสม ด้วยเหตุผลเหล่านี้คนเหล่านี้จึงเป็นคนที่ใช้ C / C ++ มากกว่า C # ฉันจะไปไกลเท่าที่ระบุนี้เป็นความจริง
ถ้าฉันไม่เข้าใจผิดเทมเพลต C # จะถูกกำหนดที่รันไทม์ สิ่งนี้จะต้องช้ากว่าเทมเพลตเวลาคอมไพล์ของ C ++
และเมื่อคุณใช้เวลาในการเพิ่มประสิทธิภาพการรวบรวมเวลาอื่น ๆ ที่กล่าวถึงโดยผู้อื่นจำนวนมากเช่นเดียวกับการขาดความปลอดภัยที่ทำจริงหมายถึงความเร็วมากขึ้น ...
ฉันจะบอกว่า C ++ เป็นตัวเลือกที่ชัดเจนในแง่ของความเร็วที่แท้จริงและการใช้หน่วยความจำขั้นต่ำ แต่สิ่งนี้ยังแปลเป็นเวลาพัฒนารหัสและมั่นใจว่าคุณจะไม่รั่วหน่วยความจำหรือทำให้เกิดข้อยกเว้นตัวชี้โมฆะใด ๆ
คำตัดสิน:
C #: การพัฒนาที่รวดเร็วขึ้นทำงานช้าลง
C ++: การพัฒนาที่ช้าวิ่งเร็วกว่า
มันขึ้นอยู่กับสิ่งที่คุณพยายามทำให้สำเร็จในรหัสของคุณ ฉันได้ยินมาว่ามันเป็นเพียงเรื่องราวของตำนานเมืองที่มีความแตกต่างของประสิทธิภาพระหว่าง VB.NET, C # และ C ++ ที่ได้รับการจัดการ อย่างไรก็ตามฉันได้พบอย่างน้อยที่สุดในการเปรียบเทียบสตริงที่มีการจัดการ C ++ เต้นกางเกงออกจาก C # ซึ่งจะตีกางเกงออกจาก VB.NET
ฉันไม่เคยทำการเปรียบเทียบที่ละเอียดถี่ถ้วนในความซับซ้อนของอัลกอริทึมระหว่างภาษา ฉันแค่ใช้การตั้งค่าเริ่มต้นในแต่ละภาษา ใน VB.NET ฉันใช้การตั้งค่าเพื่อต้องการประกาศตัวแปร ฯลฯ นี่คือรหัสที่ฉันใช้สำหรับ C ++ ที่ได้รับการจัดการ: (อย่างที่คุณเห็นรหัสนี้ค่อนข้างง่าย) ฉันใช้ภาษาเดียวกันใน Visual Studio 2013 ด้วย. NET 4.6.2
#include "stdafx.h"
using namespace System;
using namespace System::Diagnostics;
bool EqualMe(String^ first, String^ second)
{
return first->Equals(second);
}
int main(array<String ^> ^args)
{
Stopwatch^ sw = gcnew Stopwatch();
sw->Start();
for (int i = 0; i < 100000; i++)
{
EqualMe(L"one", L"two");
}
sw->Stop();
Console::WriteLine(sw->ElapsedTicks);
return 0;
}
มีความแตกต่างที่สำคัญระหว่าง C # และ C ++ ในด้านประสิทธิภาพ:
นอกจากความสามารถของโปรแกรมเมอร์ก็มีบทบาทเช่นกัน ฉันเห็นรหัส C ++ ที่ไม่ดีซึ่งคลาสที่ผ่านค่าเป็นอาร์กิวเมนต์ทั่วทุกสถานที่ คุณสามารถทำให้ประสิทธิภาพแย่ลงใน C ++ หากคุณไม่รู้ว่าคุณกำลังทำอะไรอยู่
> หลังจากทั้งหมดคำตอบจะต้องอยู่ที่ไหนสักแห่งใช่ไหม? :)
อืมมม
ตามที่ระบุไว้ในการตอบหลายคำถามนั้นมีการระบุไว้ไม่เกินในรูปแบบที่เชิญคำถามมาตอบไม่ใช่คำตอบ วิธีหนึ่ง:
แล้วโปรแกรมอะไร เครื่องไหน? ระบบปฏิบัติการใด? ชุดข้อมูลใด
โดยได้แรงบันดาลใจจากสิ่งนี้ฉันทำการทดสอบอย่างรวดเร็วโดยมีคำสั่งทั่วไป 60 เปอร์เซ็นต์ที่จำเป็นสำหรับโปรแกรมส่วนใหญ่
นี่คือรหัส C #:
for (int i=0; i<1000; i++)
{
StreamReader str = new StreamReader("file.csv");
StreamWriter stw = new StreamWriter("examp.csv");
string strL = "";
while((strL = str.ReadLine()) != null)
{
ArrayList al = new ArrayList();
string[] strline = strL.Split(',');
al.AddRange(strline);
foreach(string str1 in strline)
{
stw.Write(str1 + ",");
}
stw.Write("\n");
}
str.Close();
stw.Close();
}
อาเรย์สตริงและรายการอาร์เรย์ที่ใช้โดยเจตนาเพื่อรวมคำแนะนำ
นี่คือรหัส c ++:
for (int i = 0; i<1000; i++)
{
std::fstream file("file.csv", ios::in);
if (!file.is_open())
{
std::cout << "File not found!\n";
return 1;
}
ofstream myfile;
myfile.open ("example.txt");
std::string csvLine;
while (std::getline(file, csvLine))
{
std::istringstream csvStream(csvLine);
std::vector csvColumn;
std::string csvElement;
while( std::getline(csvStream, csvElement, ‘,’) )
{
csvColumn.push_back(csvElement);
}
for (std::vector::iterator j = csvColumn.begin(); j != csvColumn.end(); ++j)
{
myfile << *j << ", ";
}
csvColumn.clear();
csvElement.clear();
csvLine.clear();
myfile << "\n";
}
myfile.close();
file.close();
}
ขนาดอินพุตไฟล์ที่ฉันใช้คือ 40 KB
และนี่คือผลลัพธ์ -
โอ้ แต่นี่เป็นลินุกซ์ ... ด้วย C # ทำงานบนMono ... และ C ++ กับ g ++
ตกลงนี่คือสิ่งที่ฉันได้รับบน Windows - Visual Studio 2003 :