15 คะแนน โดย ttyy1234 2024-11-29 | 10 ความคิดเห็น | แชร์ทาง WhatsApp

มีการรันโปรแกรมที่ประมวลผลงานพร้อมกัน 1 ล้านงานด้วย Rust, C#, Python, Go, Java, NodeJS เวอร์ชันล่าสุด เพื่อเปรียบเทียบประสิทธิภาพด้านการใช้หน่วยความจำ

C# (NativeAOT) และ Rust แสดงประสิทธิภาพด้านหน่วยความจำได้ดีที่สุด ขณะที่ Go ได้รับการประเมินต่ำเนื่องจากใช้หน่วยความจำมากกว่าที่คาดไว้ โดยรวมแล้ว .NET และ Rust โดดเด่นเป็นพิเศษ และ Java (GraalVM) ก็แสดงให้เห็นถึงการปรับปรุงที่น่าประหลาดใจ

ในรายละเอียด Rust ใช้หน่วยความจำน้อยที่สุดที่ประมาณ 29MB ตามมาด้วย C# NativeAOT ที่ประมาณ 71MB ส่วน NodeJS อยู่ที่ 232MB และ Python อยู่ที่ 339MB ขณะที่ Go ใช้หน่วยความจำค่อนข้างสูงที่ 753MB ซึ่งเป็นผลลัพธ์ที่น่าเสียดาย ด้าน Java (GraalVM) แสดงการปรับปรุงครั้งใหญ่ด้วยการใช้หน่วยความจำเพียง 92MB

10 ความคิดเห็น

 
kroisse 2024-12-02

เมื่อดูโค้ดเบนช์มาร์กแล้ว ในกรณีของ Rust และ Python ดูเหมือนว่าในความเป็นจริงไม่ได้สร้าง concurrent task ขึ้นมา แต่เป็นเพียงการสร้างอ็อบเจ็กต์ future ที่แม้จะทำงานแบบ asynchronous แต่ก็ไม่สามารถรันแบบขนานกับ task อื่นได้จริง ผมคิดว่า C# ก็น่าจะเป็นกรณีคล้ายกัน ในทางกลับกัน โค้ด Go ถูกออกแบบมาให้สร้าง goroutine ซึ่งเป็น task ที่มี call stack เป็นต้น เป็นของตัวเอง ดังนั้นสาเหตุที่การใช้หน่วยความจำของ Go ดูพุ่งผิดปกติโดยเฉพาะในเคส 1 ล้านรายการ ก็น่าจะมาจากจุดนี้

 
bungker 2024-11-30

ถ้าจะพูดปกป้อง Go ล่ะก็ Go สามารถทำงานได้แม้จะมีไลบรารีอะไรก็ตามอยู่ภายในฟังก์ชันที่รันพร้อมกัน 1 ล้านตัว แค่ใส่ go ก็พอแล้ว ในภาษาอื่นที่อิง async ถ้ามีไลบรารีแบบ synchronous แทรกอยู่ตรงกลางและกินเวลาแม้เพียงเล็กน้อย มันก็อาจกลายเป็นสถานการณ์ชวนปวดหัวที่ข้อดีของ async ถูกกลบหายไปหมด เพื่อใช้ประโยชน์จาก async ได้อย่างเต็ม 100% ฟังก์ชันทุกตัวที่กินเวลาแม้แต่นิดเดียวก็ต้องเปลี่ยนให้เป็น async ทั้งหมด ส่วน Java VirtualThread นี่ก็... รอบนี้ที่บริษัทของเราเคยเชื่อมั่นแล้วเดินหน้าด้วย Java VirtualThread แต่สุดท้ายเพราะปัญหาความเข้ากันได้กับไลบรารี ก็ต้องเปลี่ยนกลับไปใช้ thread ปกติ แล้วจบลงด้วยการต้องเปิดอินสแตนซ์หลายสิบตัว

 
roxie 2024-12-01

ขอฟังเพิ่มเติมเกี่ยวกับส่วนของความเข้ากันได้อีกหน่อยได้ไหมครับ :eyes:

 
secret3056 2024-12-02

คงพูดได้ว่าไม่มีคำกล่าวที่มักได้ยินใน Spring ว่า "ถ้าจะใช้ WebFlux ให้ได้อย่างถูกต้อง ต้องใช้กับ R2DBC แทน JPA ถึงจะเห็นคุณค่าที่แท้จริง"

 
bungker 2024-12-01

ได้ยินมาว่าไลบรารี msal ของ Microsoft ไม่ทำงานบน virtual thread

 
vwjdalsgkv 2024-12-02

ผมคิดว่าในกรณีของไลบรารี msal ที่ยกมาเป็นตัวอย่าง หากในฝั่ง Go ก็เป็นไลบรารีที่ใช้ชนิดข้อมูลหรือโครงสร้างที่ไม่ thread-safe เช่นกัน ก็น่าจะเป็นเคสแบบเดียวกัน

 
riki3 2024-12-02

มันเกี่ยวข้องกับ thread safety ตรงไหนหรือครับ? แต่เดิม goroutine ก็ไม่ใช่ระบบที่รับประกัน thread safety อยู่แล้วไม่ใช่หรือครับ

 
hookim 2024-11-30

ขอบคุณสำหรับข้อมูลครับ

มีคำถามที่อยากถามครับ
ถ้าอย่างนั้น ภาษาอื่น ๆ นอกจาก Go ถ้ามีไลบรารีแบบ synchronous อย่างที่คุณบอกไว้ ก็จะพังหมดเลยใช่ไหมครับ?
หรือว่าจริง ๆ แล้วในบรรดาภาษาอื่น ๆ ก็มีภาษาที่รองรับ asynchronous ได้อย่างสมบูรณ์แบบเหมือน Go ด้วยหรือเปล่า อยากทราบครับ

 
riki3 2024-11-30

มีคำว่า colorless อยู่ ภาษาที่ไม่จำเป็นต้องแยกระหว่างอะซิงโครนัสกับซิงโครนัสนั้นมีแค่ Go เท่านั้น จากมุมมองของผู้ใช้ เมื่อต้องเขียนโปรแกรมที่ต้องการ concurrency แล้ว Go มีจุดแข็งที่เหนือกว่ามากในด้านความยากและการใช้งาน
แม้ประสิทธิภาพอาจด้อยกว่าการเขียนโปรแกรมอะซิงโครนัสที่ปรับแต่งมาอย่างดีอยู่เล็กน้อยก็ตาม

 
bungker 2024-11-30

ขออภัยที่ต้องทักนะครับ แต่ผมจะขอพูดเฉพาะส่วนที่ไม่ถูกต้องของคำว่า “พัง” และคำว่า “อะซิงก์ที่สมบูรณ์แบบ” เท่านั้นครับ แม้จะเป็นแบบอะซิงก์ก็ใช้ไลบรารีแบบซิงก์ได้ ไม่มีปัญหา ตราบใดที่รับประกันได้ว่าจะเสร็จภายในเวลาสั้น ๆ ถ้ามีการเรียกแบบซิงก์ที่ใช้เวลารันนาน ก็จะทำให้การประมวลผลอะซิงก์อื่น ๆ ช้าลง จึงเกิดปัญหาครับ ส่วน Go สามารถจัดสรรงานระดับหลายร้อยล้านงานด้วย goroutine ได้ ดังนั้นตัวภาษาเองจึงไม่มีแนวคิดเรื่องอะซิงก์ในตัว จากมุมของคนใช้งาน แค่เรียกฟังก์ชันใด ๆ โดยเติม go เข้าไป ก็จะรันแบบขนานได้เลย สะดวกมากครับ ส่วนตัวผมคิดว่า “อะซิงก์ที่สมบูรณ์แบบ” น่าจะเป็น JavaScript เพราะรากฐานของภาษานั้นเป็นอะซิงก์ครับ