นี่คือข้อโต้แย้งของฉันว่าทำไมการเขียนโปรแกรมแบบใช้งานได้และควรใช้สำหรับวิทยาศาสตร์การคำนวณ ประโยชน์มีมากมายและข้อเสียกำลังหายไปอย่างรวดเร็ว ในใจของฉันมีเพียงคนเดียวแย้ง:
ข้อเสีย : ไม่มีการสนับสนุนด้านภาษาใน C / C ++ / Fortran
อย่างน้อยใน C ++ คอนเวอร์ชันนี้จะหายไปเนื่องจาก C ++ 14/17 ได้เพิ่มสิ่งอำนวยความสะดวกที่มีประสิทธิภาพเพื่อรองรับการเขียนโปรแกรมที่ใช้งานได้ คุณอาจต้องเขียนไลบรารี่ / รหัสสนับสนุนด้วยตัวเอง แต่ภาษานั้นจะเป็นเพื่อนของคุณ เป็นตัวอย่างที่นี่เป็น (คำเตือน: ปลั๊ก) ห้องสมุดที่ไม่เปลี่ยนรูปอาร์เรย์หลายมิติใน C ++: https://github.com/jzrake/ndarray-v2
นอกจากนี้นี่คือลิงก์ไปยังหนังสือที่ดีเกี่ยวกับการเขียนโปรแกรมเชิงฟังก์ชันใน C ++ แม้ว่ามันจะไม่ได้เน้นที่การใช้งานทางวิทยาศาสตร์
นี่คือบทสรุปของสิ่งที่ฉันเชื่อว่าเป็นมืออาชีพ:
ข้อดี :
- ความถูกต้อง
- สามารถทำความเข้าใจได้
- ประสิทธิภาพ
ในแง่ของความถูกต้องโปรแกรมการใช้งานจะถูกจัดวางอย่างดี : พวกมันบังคับให้คุณกำหนดสถานะของตัวแปรฟิสิกส์ของคุณให้น้อยที่สุดและฟังก์ชั่นที่เลื่อนไปข้างหน้าตามเวลา
int main()
{
auto state = initial_condition();
while (should_continue(state))
{
state = advance(state);
side_effects(state);
}
return 0;
}
การแก้สมการเชิงอนุพันธ์ย่อยบางส่วน (หรือ ODE) เหมาะสำหรับการโปรแกรมเชิงฟังก์ชัน คุณเพิ่งใช้ฟังก์ชั่น pure ( advance
) กับโซลูชันปัจจุบันเพื่อสร้างฟังก์ชันถัดไป
จากประสบการณ์ของผมซอฟต์แวร์จำลองฟิสิกส์คือโดยและขนาดใหญ่ภาระโดยที่ไม่ดีการจัดการของรัฐ โดยปกติแต่ละขั้นตอนของอัลกอริทึมจะทำงานในบางส่วนของสถานะที่ใช้ร่วมกัน (มีประสิทธิภาพทั่วโลก) สิ่งนี้ทำให้เป็นเรื่องยากหรือเป็นไปไม่ได้แม้แต่ในการรับรองลำดับการดำเนินการที่ถูกต้องปล่อยให้ซอฟต์แวร์ที่มีความเสี่ยงต่อข้อผิดพลาดที่สามารถแสดงให้เห็นว่าเป็นข้อผิดพลาดหรือแย่กว่านั้นคือข้อผิดพลาดที่ไม่ผิดพลาดรหัสของคุณ เอาท์พุต ความพยายามในการจัดการสถานะที่ใช้ร่วมกันในการจำลองทางฟิสิกส์ยังช่วยยับยั้งมัลติเธรดซึ่งเป็นปัญหาสำหรับอนาคตเนื่องจากซูเปอร์คอมพิวเตอร์กำลังเคลื่อนไปสู่การนับแกนกลางที่สูงขึ้นและการปรับสเกลด้วย MPI มักทำหน้าที่ได้สูงสุด ~ 100k ในทางตรงกันข้ามการตั้งโปรแกรมการทำงานทำให้ความเท่าเทียมกันของหน่วยความจำที่ใช้ร่วมกันเป็นเรื่องเล็กน้อยเนื่องจากความไม่สามารถเปลี่ยนแปลงได้
ประสิทธิภาพยังได้รับการปรับปรุงในการเขียนโปรแกรมเชิงฟังก์ชันเนื่องจากการประเมินอัลกอริธึมที่ขี้เกียจ (ใน C ++ หมายถึงการสร้างหลายประเภทในเวลาคอมไพล์ - บ่อยครั้งหนึ่งสำหรับแต่ละแอปพลิเคชันของฟังก์ชัน) แต่จะช่วยลดค่าใช้จ่ายในการเข้าถึงและการจัดสรรหน่วยความจำรวมถึงกำจัดการแจกจ่ายเสมือน - ช่วยให้คอมไพเลอร์สามารถปรับแต่งอัลกอริทึมทั้งหมดโดยการดูทันทีที่วัตถุฟังก์ชั่นทั้งหมดประกอบด้วย ในทางปฏิบัติคุณจะทดลองกับการจัดเรียงคะแนนการประเมินที่แตกต่างกัน (ซึ่งผลลัพธ์อัลกอริทึมถูกแคชกับบัฟเฟอร์หน่วยความจำ) เพื่อเพิ่มประสิทธิภาพการใช้ CPU กับการจัดสรรหน่วยความจำ สิ่งนี้ค่อนข้างง่ายเนื่องจากตำแหน่งสูง (ดูตัวอย่างด้านล่าง) ของขั้นตอนวิธีเปรียบเทียบกับสิ่งที่คุณมักจะเห็นในโมดูลหรือรหัสตามคลาส
โปรแกรมการทำงานนั้นง่ายต่อการเข้าใจตราบเท่าที่พวกเขาทำรัฐประหารฟิสิกส์เล็กน้อย ไม่ได้บอกว่าเพื่อนร่วมงานของคุณทุกคนเข้าใจไวยากรณ์ได้ง่าย! ผู้เขียนควรระมัดระวังในการใช้ฟังก์ชั่นที่มีชื่อและนักวิจัยโดยทั่วไปควรคุ้นเคยกับการเห็นอัลกอริธึมที่แสดงออกมาในเชิงปฏิบัติแทนที่จะเป็นขั้นตอน ฉันจะยอมรับว่าการไม่มีโครงสร้างการควบคุมอาจทำให้บางคนไม่ชอบ แต่ฉันไม่คิดว่ามันจะหยุดพวกเราไม่ให้ไปสู่อนาคตที่จะทำวิทยาศาสตร์ที่มีคุณภาพดีกว่าบนคอมพิวเตอร์
ด้านล่างเป็นadvance
ฟังก์ชั่นตัวอย่างซึ่งดัดแปลงมาจากรหัสปริมาณ จำกัด โดยใช้ndarray-v2
แพ็คเกจ สังเกตto_shared
ผู้ดำเนินการ - นี่คือคะแนนการประเมินที่ฉันพูดถึงก่อนหน้านี้
auto advance(const solution_state_t& state)
{
auto dt = determine_time_step_size(state);
auto du = state.u
| divide(state.vertices | volume_from_vertices)
| nd::map(recover_primitive)
| extrapolate_boundary_on_axis(0)
| nd::to_shared()
| compute_intercell_flux(0)
| nd::to_shared()
| nd::difference_on_axis(0)
| nd::multiply(-dt * mara::make_area(1.0));
return solution_state_t {
state.time + dt,
state.iteration + 1,
state.vertices,
state.u + du | nd::to_shared() };
}