บทสัมภาษณ์ดีๆ กับ Cliff Click บิดาแห่งการรวบรวม JIT ใน Java

บทสัมภาษณ์ดีๆ กับ Cliff Click บิดาแห่งการรวบรวม JIT ใน Javaคลิ้กคลิก — CTO ของ Cratus (เซ็นเซอร์ IoT สำหรับการปรับปรุงกระบวนการ) ผู้ก่อตั้งและผู้ร่วมก่อตั้งบริษัทสตาร์ทอัพหลายแห่ง (รวมถึง Rocket Realtime School, Neurensic และ H2O.ai) ที่ประสบความสำเร็จหลายราย Cliff เขียนคอมไพเลอร์ตัวแรกเมื่ออายุ 15 ปี (Pascal สำหรับ TRS Z-80)! เขาเป็นที่รู้จักกันเป็นอย่างดีจากผลงานของเขาใน C2 ใน Java (Sea of ​​​​Nodes IR) คอมไพเลอร์นี้แสดงให้โลกเห็นว่า JIT สามารถสร้างโค้ดคุณภาพสูงได้ ซึ่งเป็นหนึ่งในปัจจัยที่ทำให้ Java เป็นหนึ่งในแพลตฟอร์มซอฟต์แวร์หลักสมัยใหม่ จากนั้น Cliff ช่วย Azul Systems สร้างเมนเฟรม 864 คอร์ด้วยซอฟต์แวร์ Java ล้วนๆ ที่รองรับ GC หยุดชั่วคราวบนฮีปขนาด 500 กิกะไบต์ภายใน 10 มิลลิวินาที โดยทั่วไปแล้ว Cliff สามารถทำงานในทุกด้านของ JVM ได้

 
ฮาบราโพสต์นี้เป็นบทสัมภาษณ์ที่ยอดเยี่ยมของคลิฟ เราจะพูดคุยในหัวข้อต่อไปนี้:

  • เปลี่ยนไปใช้การเพิ่มประสิทธิภาพระดับต่ำ
  • วิธีการรีแฟคเตอร์ครั้งใหญ่
  • โมเดลต้นทุน
  • การฝึกอบรมการเพิ่มประสิทธิภาพระดับต่ำ
  • ตัวอย่างการปฏิบัติของการปรับปรุงประสิทธิภาพ
  • ทำไมต้องสร้างภาษาโปรแกรมของคุณเอง
  • อาชีพวิศวกรประสิทธิภาพ
  • ความท้าทายทางเทคนิค
  • เล็กน้อยเกี่ยวกับการจัดสรรการลงทะเบียนและมัลติคอร์
  • ความท้าทายที่ยิ่งใหญ่ที่สุดในชีวิต

การสัมภาษณ์ดำเนินการโดย:

  • อันเดรย์ ซาทาริน จากอเมซอนเว็บเซอร์วิส ในอาชีพของเขา เขาสามารถทำงานในโครงการที่แตกต่างกันโดยสิ้นเชิง: เขาทดสอบฐานข้อมูลแบบกระจาย NewSQL ใน Yandex, ระบบตรวจจับคลาวด์ใน Kaspersky Lab, เกมที่มีผู้เล่นหลายคนใน Mail.ru และบริการสำหรับการคำนวณราคาแลกเปลี่ยนเงินตราต่างประเทศใน Deutsche Bank สนใจทดสอบระบบแบ็กเอนด์ขนาดใหญ่และระบบแบบกระจาย
  • วลาดิมีร์ ซิตนิคอฟ จากเน็ตแครกเกอร์ ผลงานสิบปีในด้านประสิทธิภาพและความสามารถในการปรับขนาดของ NetCracker OS ซึ่งเป็นซอฟต์แวร์ที่ผู้ให้บริการโทรคมนาคมใช้เพื่อทำให้กระบวนการจัดการเครือข่ายและอุปกรณ์เครือข่ายเป็นแบบอัตโนมัติ สนใจปัญหาด้านประสิทธิภาพของ Java และ Oracle Database ผู้เขียนการปรับปรุงประสิทธิภาพมากกว่าหนึ่งโหลในไดรเวอร์ PostgreSQL JDBC อย่างเป็นทางการ

เปลี่ยนไปใช้การเพิ่มประสิทธิภาพระดับต่ำ

แอนดรู: คุณเป็นชื่อที่ยิ่งใหญ่ในโลกของการคอมไพล์ JIT, Java และงานด้านประสิทธิภาพโดยทั่วไปใช่ไหม? 

หน้าผา: ประมาณนั้นแหละ!

แอนดรู: เริ่มจากคำถามทั่วไปเกี่ยวกับประสิทธิภาพการทำงานกันก่อน คุณคิดอย่างไรเกี่ยวกับตัวเลือกระหว่างการเพิ่มประสิทธิภาพระดับสูงและระดับต่ำ เช่น การทำงานในระดับ CPU

หน้าผา: ใช่ ทุกอย่างเรียบง่ายที่นี่ รหัสที่เร็วที่สุดคือรหัสที่ไม่เคยทำงาน ดังนั้นคุณต้องเริ่มจากระดับสูงเสมอและทำงานกับอัลกอริธึม สัญกรณ์ O ที่ดีกว่าจะเอาชนะสัญกรณ์ O ที่แย่กว่า เว้นแต่ว่าค่าคงที่ที่มีขนาดใหญ่เพียงพอจะเข้ามาแทรกแซง สิ่งระดับต่ำจะคงอยู่ต่อไป โดยทั่วไป หากคุณเพิ่มประสิทธิภาพสแต็กที่เหลือได้ดีเพียงพอและยังมีสิ่งที่น่าสนใจเหลืออยู่ นั่นถือเป็นระดับต่ำ แต่จะเริ่มต้นจากระดับสูงได้อย่างไร? คุณรู้ได้อย่างไรว่างานระดับสูงได้เสร็จสิ้นไปเพียงพอแล้ว? ก็...ไม่มีทาง ไม่มีสูตรสำเร็จรูป คุณต้องเข้าใจปัญหา ตัดสินใจว่าคุณกำลังจะทำอะไร (เพื่อไม่ให้เกิดขั้นตอนที่ไม่จำเป็นในอนาคต) จากนั้นคุณจะสามารถเปิดเผยโปรไฟล์ที่สามารถพูดสิ่งที่มีประโยชน์ได้ เมื่อถึงจุดหนึ่ง คุณเองก็ตระหนักได้ว่าคุณได้กำจัดสิ่งที่ไม่จำเป็นออกไปแล้ว และถึงเวลาที่จะต้องปรับแต่งอย่างละเอียดในระดับต่ำ นี่เป็นงานศิลปะประเภทพิเศษอย่างแน่นอน มีคนจำนวนมากทำสิ่งที่ไม่จำเป็น แต่ดำเนินไปอย่างรวดเร็วจนไม่มีเวลากังวลเกี่ยวกับประสิทธิภาพการทำงาน แต่นี่เป็นจนกระทั่งคำถามเกิดขึ้นอย่างโผงผาง โดยปกติแล้ว 99% ของเวลาที่ไม่มีใครสนใจสิ่งที่ฉันทำ จนกระทั่งช่วงเวลาที่สิ่งสำคัญเข้ามาบนเส้นทางวิกฤติที่ไม่มีใครสนใจ และที่นี่ทุกคนเริ่มบ่นคุณว่า "ทำไมมันทำงานได้ไม่สมบูรณ์ตั้งแต่แรกเริ่ม" โดยทั่วไปแล้ว มีบางสิ่งที่ต้องปรับปรุงประสิทธิภาพอยู่เสมอ แต่ 99% ของคุณไม่มีโอกาสในการขาย! คุณแค่พยายามทำอะไรบางอย่างให้ได้ผล และในกระบวนการนี้คุณก็จะรู้ว่าอะไรสำคัญ คุณไม่สามารถรู้ล่วงหน้าได้ว่างานชิ้นนี้จะต้องสมบูรณ์แบบ ดังนั้นในความเป็นจริงแล้ว คุณจะต้องสมบูรณ์แบบในทุกสิ่ง แต่นี่เป็นไปไม่ได้และคุณไม่ทำมัน มีหลายสิ่งที่ต้องแก้ไขอยู่เสมอ และนั่นเป็นเรื่องปกติโดยสิ้นเชิง

วิธีการรีแฟคเตอร์ครั้งใหญ่

แอนดรู: คุณทำงานการแสดงเป็นอย่างไรบ้าง? นี่เป็นปัญหาที่ตัดขวาง ตัวอย่างเช่น คุณเคยต้องแก้ไขปัญหาที่เกิดจากการทับซ้อนกันของฟังก์ชันการทำงานที่มีอยู่มากมายหรือไม่?

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

โมเดลต้นทุน

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

หน้าผา: แน่นอน. ฉันเกิดในยุคที่ประสิทธิภาพของโปรเซสเซอร์มีความสำคัญอย่างยิ่ง และยุคนี้กลับมาอีกครั้ง - โชคชะตาไม่ได้ไร้การประชด ฉันเริ่มใช้ชีวิตในยุคของเครื่อง 256 บิต คอมพิวเตอร์เครื่องแรกของฉันใช้งานได้ XNUMX ไบต์ ไบต์ที่แน่นอน ทุกอย่างเล็กมาก จำเป็นต้องนับคำสั่ง และเมื่อเราเริ่มขยับสแต็กภาษาการเขียนโปรแกรม ภาษาต่างๆ ก็เข้ามามากขึ้นเรื่อยๆ มี Assembler ตามด้วย Basic จากนั้น C และ C ดูแลรายละเอียดมากมาย เช่น การจัดสรรรีจิสเตอร์และการเลือกคำสั่ง แต่ทุกอย่างชัดเจนที่นั่น และถ้าฉันสร้างตัวชี้ไปยังอินสแตนซ์ของตัวแปร ฉันก็จะโหลด และทราบราคาของคำสั่งนี้ ฮาร์ดแวร์สร้างรอบเครื่องจักรตามจำนวนที่กำหนด ดังนั้นความเร็วในการดำเนินการของสิ่งต่างๆ จึงสามารถคำนวณได้ง่ายๆ โดยการเพิ่มคำสั่งทั้งหมดที่คุณจะเรียกใช้ การเปรียบเทียบ/ทดสอบ/สาขา/การโทร/โหลด/ร้านค้าแต่ละรายการสามารถเพิ่มและกล่าวว่า นั่นคือเวลาดำเนินการสำหรับคุณ เมื่อปรับปรุงประสิทธิภาพ คุณจะต้องใส่ใจอย่างแน่นอนว่าตัวเลขใดที่สอดคล้องกับรอบร้อนเล็กน้อย 
แต่ทันทีที่คุณเปลี่ยนมาใช้ Java, Python และสิ่งที่คล้ายกัน คุณจะย้ายออกจากฮาร์ดแวร์ระดับต่ำอย่างรวดเร็ว ค่าใช้จ่ายในการเรียกทะเยอทะยานใน Java คืออะไร? หาก JIT ใน HotSpot ถูกต้อง อินไลน์มันจะโหลด แต่ถ้าไม่ทำเช่นนี้ มันจะเป็นการเรียกใช้ฟังก์ชัน เนื่องจากการโทรอยู่ในฮอตลูป การโทรจะแทนที่การปรับให้เหมาะสมอื่นๆ ทั้งหมดในลูปนั้น ดังนั้นต้นทุนที่แท้จริงจะสูงกว่ามาก และคุณจะสูญเสียความสามารถในการดูโค้ดทันทีและเข้าใจว่าเราควรดำเนินการมันในแง่ของความเร็วสัญญาณนาฬิกาของโปรเซสเซอร์ หน่วยความจำ และแคชที่ใช้ ทั้งหมดนี้น่าสนใจก็ต่อเมื่อคุณได้เข้าสู่การแสดงจริงๆ
ตอนนี้เราพบว่าตัวเองอยู่ในสถานการณ์ที่ความเร็วของโปรเซสเซอร์แทบจะไม่เพิ่มขึ้นเลยในรอบทศวรรษ วันเก่าๆกลับมาแล้ว! คุณไม่สามารถวางใจในประสิทธิภาพแบบเธรดเดียวที่ดีได้อีกต่อไป แต่ถ้าคุณเข้าสู่การประมวลผลแบบคู่ขนาน มันจะเป็นเรื่องยากอย่างไม่น่าเชื่อ ทุกคนมองคุณเหมือนกับ James Bond ความเร่งสิบเท่าที่นี่มักเกิดขึ้นในสถานที่ที่มีคนทำบางสิ่งผิดพลาด การเห็นพ้องต้องกันต้องทำงานมาก หากต้องการเร่งความเร็ว XNUMX เท่า คุณต้องเข้าใจโมเดลต้นทุน อะไรและราคาเท่าไหร่? และในการทำเช่นนี้ คุณต้องเข้าใจว่าลิ้นเข้ากับฮาร์ดแวร์ที่ซ่อนอยู่ได้อย่างไร
Martin Thompson เลือกคำที่ยอดเยี่ยมสำหรับบล็อกของเขา ความเห็นอกเห็นใจทางกล! คุณต้องเข้าใจว่าฮาร์ดแวร์กำลังทำอะไร จริงๆ แล้วมันจะทำอะไร และทำไมมันถึงทำในสิ่งที่มันทำตั้งแต่แรก เมื่อใช้สิ่งนี้ มันค่อนข้างง่ายที่จะเริ่มนับคำสั่งและหาว่าเวลาดำเนินการจะไปที่ใด หากคุณไม่ได้รับการฝึกที่เหมาะสม คุณก็แค่มองหาแมวดำในห้องมืด ฉันเห็นผู้คนเพิ่มประสิทธิภาพการทำงานตลอดเวลาโดยไม่รู้ว่าพวกเขากำลังทำอะไรอยู่ พวกเขาทนทุกข์ทรมานมากและไม่ก้าวหน้ามากนัก และเมื่อฉันใช้โค้ดชิ้นเดียวกัน แอบแฮ็กเล็กๆ น้อยๆ สองสามอย่างและเร่งความเร็วขึ้นห้าหรือสิบเท่า พวกมันก็แบบว่า มันไม่ยุติธรรมเลย เรารู้อยู่แล้วว่าคุณเก่งกว่า อัศจรรย์. ฉันกำลังพูดถึงอะไร... โมเดลต้นทุนนั้นเกี่ยวกับโค้ดประเภทที่คุณเขียน และความเร็วโดยเฉลี่ยในภาพรวม

แอนดรู: และคุณจะรักษาระดับเสียงไว้ในหัวได้อย่างไร? สิ่งนี้สำเร็จได้ด้วยประสบการณ์ที่มากขึ้นหรือ? ประสบการณ์ดังกล่าวมาจากไหน?

หน้าผา: ฉันไม่ได้รับประสบการณ์ด้วยวิธีที่ง่ายที่สุด ฉันเขียนโปรแกรมใน Assembly ย้อนกลับไปในสมัยที่คุณสามารถเข้าใจทุกคำสั่งได้ ฟังดูงี่เง่า แต่ตั้งแต่นั้นมาชุดคำสั่ง Z80 ก็ยังคงอยู่ในหัวของฉันเสมอในความทรงจำของฉัน ฉันจำชื่อคนไม่ได้ในเวลาพูดคุยเพียงนาทีเดียว แต่ฉันจำโค้ดที่เขียนเมื่อ 40 ปีที่แล้วได้ ตลกดี ดูเหมือนซินโดรมเลย”นักวิทยาศาสตร์งี่เง่า'

การฝึกอบรมการเพิ่มประสิทธิภาพระดับต่ำ

แอนดรู: มีวิธีที่ง่ายกว่านี้ไหม?

หน้าผา: ใช่และไม่. ฮาร์ดแวร์ที่เราใช้ทั้งหมดไม่ได้เปลี่ยนแปลงไปมากนักเมื่อเวลาผ่านไป ทุกคนใช้ x86 ยกเว้นสมาร์ทโฟน Arm หากคุณไม่ได้ทำการฝังแบบฮาร์ดคอร์ คุณก็กำลังทำสิ่งเดียวกัน เอาล่ะต่อไป คำแนะนำยังไม่มีการเปลี่ยนแปลงมานานหลายศตวรรษ คุณต้องไปเขียนอะไรบางอย่างใน Assembly ไม่มากแต่ก็เพียงพอให้เริ่มเข้าใจ คุณกำลังยิ้ม แต่ฉันพูดอย่างจริงจังจริงๆ คุณต้องเข้าใจความสอดคล้องระหว่างภาษาและฮาร์ดแวร์ หลังจากนั้นคุณต้องไปเขียนนิดหน่อยและสร้างคอมไพเลอร์ของเล่นเล็กๆ สำหรับภาษาของเล่นเล็กๆ น้อยๆ ของเล่นเหมือนหมายความว่าจะต้องทำในระยะเวลาที่เหมาะสม มันอาจจะง่ายมาก แต่ต้องสร้างคำแนะนำ การสร้างคำสั่งจะช่วยให้คุณเข้าใจโมเดลต้นทุนสำหรับการเชื่อมโยงระหว่างโค้ดระดับสูงที่ทุกคนเขียนและโค้ดเครื่องที่ทำงานบนฮาร์ดแวร์ จดหมายโต้ตอบนี้จะถูกเบิร์นเข้าสู่สมองในขณะที่เขียนคอมไพเลอร์ แม้แต่คอมไพเลอร์ที่ง่ายที่สุด หลังจากนั้น คุณสามารถเริ่มดูที่ Java และความจริงที่ว่าช่องว่างทางความหมายของมันนั้นลึกกว่ามากและการสร้างสะพานข้ามมันนั้นยากกว่ามาก ในชวา มันยากกว่ามากที่จะเข้าใจว่าสะพานของเราออกมาดีหรือไม่ดี อะไรจะทำให้มันพัง และอะไรจะไม่พัง แต่คุณจำเป็นต้องมีจุดเริ่มต้นที่คุณดูโค้ดและทำความเข้าใจ: “ใช่แล้ว ผู้ทะเยอทะยานนี้ควรถูกแทรกในบรรทัดทุกครั้ง” จากนั้นปรากฎว่าบางครั้งสิ่งนี้เกิดขึ้น ยกเว้นสถานการณ์ที่วิธีการมีขนาดใหญ่เกินไป และ JIT ก็เริ่มแทรกทุกอย่างเข้าไป สามารถคาดการณ์ประสิทธิภาพของสถานที่ดังกล่าวได้ทันที โดยปกติแล้ว getter จะทำงานได้ดี แต่เมื่อคุณดู hot loop ขนาดใหญ่แล้วพบว่ามีการเรียกใช้ฟังก์ชันบางอย่างลอยอยู่รอบๆ ซึ่งไม่รู้ว่ากำลังทำอะไรอยู่ นี่คือปัญหาของการใช้ getter อย่างแพร่หลาย เหตุผลที่ว่าทำไมพวกมันไม่อยู่ในบรรทัดก็คือ ยังไม่ชัดเจนว่าพวกมันคือทะเยอทะยานหรือไม่ หากคุณมี Code Base ที่เล็กมาก คุณสามารถจำมันได้แล้วพูดว่า: นี่คือ getter และนี่คือ setter ในฐานโค้ดขนาดใหญ่ แต่ละฟังก์ชันจะมีประวัติของตัวเอง ซึ่งโดยทั่วไปแล้วไม่มีใครรู้จัก Profiler บอกว่าเราเสียเวลาไป 24% ในบางลูป และเพื่อทำความเข้าใจว่าลูปนี้กำลังทำอะไรอยู่ เราต้องดูแต่ละฟังก์ชันข้างใน เป็นไปไม่ได้ที่จะเข้าใจสิ่งนี้หากไม่ได้ศึกษาฟังก์ชันนี้ และทำให้กระบวนการทำความเข้าใจช้าลงอย่างมาก นั่นเป็นเหตุผลว่าทำไมฉันถึงไม่ใช้ getters และ setters ฉันมาถึงระดับใหม่แล้ว!
จะหาโมเดลต้นทุนได้ที่ไหน? แน่นอนว่าคุณสามารถอ่านอะไรบางอย่างได้... แต่ฉันคิดว่าวิธีที่ดีที่สุดคือลงมือทำ การสร้างคอมไพเลอร์ขนาดเล็กจะเป็นวิธีที่ดีที่สุดในการทำความเข้าใจโมเดลต้นทุนและปรับให้เข้ากับความคิดของคุณเอง คอมไพเลอร์ขนาดเล็กที่เหมาะสำหรับการเขียนโปรแกรมไมโครเวฟถือเป็นงานสำหรับมือใหม่ ฉันหมายถึงถ้าคุณมีทักษะการเขียนโปรแกรมอยู่แล้วนั่นก็น่าจะเพียงพอแล้ว สิ่งเหล่านี้ทั้งหมดเช่นการแยกวิเคราะห์สตริงที่คุณมีเป็นนิพจน์พีชคณิตบางประเภทการแยกคำแนะนำสำหรับการดำเนินการทางคณิตศาสตร์จากที่นั่นตามลำดับที่ถูกต้องรับค่าที่ถูกต้องจากรีจิสเตอร์ - ทั้งหมดนี้เสร็จสิ้นในคราวเดียว และในขณะที่คุณทำมัน มันจะตราตรึงอยู่ในสมองของคุณ ฉันคิดว่าทุกคนรู้ว่าคอมไพเลอร์ทำอะไร และนี่จะทำให้มีความเข้าใจเกี่ยวกับแบบจำลองต้นทุน

ตัวอย่างการปฏิบัติของการปรับปรุงประสิทธิภาพ

แอนดรู: คุณควรใส่ใจอะไรอีกบ้างเมื่อทำงานด้านประสิทธิภาพการทำงาน?

หน้าผา: โครงสร้างข้อมูล ยังไงก็ตาม ใช่ ฉันไม่ได้สอนวิชาพวกนี้มานานแล้ว... โรงเรียนจรวด. มันสนุก แต่ต้องใช้ความพยายามอย่างมาก และฉันก็มีชีวิตด้วย! ตกลง. ดังนั้น ในชั้นเรียนใหญ่และน่าสนใจชั้นเรียนหนึ่ง "ผลงานของคุณไปไหน" ฉันยกตัวอย่างให้นักเรียนฟัง ข้อมูลฟินเทคสองกิกะไบต์ครึ่งถูกอ่านจากไฟล์ CSV จากนั้นนักเรียนจะต้องคำนวณจำนวนผลิตภัณฑ์ที่ขาย . ข้อมูลตลาดติ๊กปกติ แพ็กเก็ต UDP แปลงเป็นรูปแบบข้อความตั้งแต่ยุค 70 Chicago Mercantile Exchange - ทุกประเภท เช่น เนย ข้าวโพด ถั่วเหลือง อะไรทำนองนั้น จำเป็นต้องนับผลิตภัณฑ์เหล่านี้ จำนวนธุรกรรม ปริมาณการเคลื่อนไหวของเงินทุนและสินค้าโดยเฉลี่ย เป็นต้น คณิตศาสตร์การซื้อขายค่อนข้างง่าย: ค้นหารหัสผลิตภัณฑ์ (นั่นคือ 1-2 ตัวอักษรในตารางแฮช) รับจำนวนเงิน เพิ่มลงในชุดการซื้อขายชุดใดชุดหนึ่ง เพิ่มปริมาณ เพิ่มมูลค่า และอีกสองสามอย่าง คณิตศาสตร์ที่ง่ายมาก การใช้งานของเล่นนั้นตรงไปตรงมามาก: ทุกอย่างอยู่ในไฟล์ ฉันอ่านไฟล์และเลื่อนดูมัน แบ่งบันทึกแต่ละรายการออกเป็นสตริง Java ค้นหาสิ่งที่จำเป็นในนั้นและเพิ่มตามคณิตศาสตร์ที่อธิบายไว้ข้างต้น และมันทำงานด้วยความเร็วต่ำพอสมควร

ด้วยแนวทางนี้ มันชัดเจนว่าเกิดอะไรขึ้น และการประมวลผลแบบคู่ขนานไม่ได้ช่วยอะไรใช่ไหม ปรากฎว่าสามารถเพิ่มประสิทธิภาพได้ถึงห้าเท่าได้ง่ายๆ โดยการเลือกโครงสร้างข้อมูลที่เหมาะสม และสิ่งนี้ทำให้แม้แต่โปรแกรมเมอร์ที่มีประสบการณ์ก็ประหลาดใจ! ในกรณีเฉพาะของฉัน เคล็ดลับคือคุณไม่ควรทำการจัดสรรหน่วยความจำในฮอตลูป นี่ไม่ใช่ความจริงทั้งหมด แต่โดยทั่วไป - คุณไม่ควรเน้น "ครั้งหนึ่งใน X" เมื่อ X มีขนาดใหญ่พอ เมื่อ X มีขนาดสองกิกะไบต์ครึ่ง คุณไม่ควรจัดสรรสิ่งใดๆ "หนึ่งครั้งต่อตัวอักษร" หรือ "หนึ่งครั้งต่อบรรทัด" หรือ "หนึ่งครั้งต่อฟิลด์" อะไรทำนองนั้น นี่คือที่ที่ใช้เวลา สิ่งนี้ทำงานได้อย่างไร? ลองนึกภาพฉันกำลังโทรออก String.split() หรือ BufferedReader.readLine(). Readline สร้างสตริงจากชุดไบต์ที่ส่งผ่านเครือข่าย หนึ่งครั้งสำหรับแต่ละบรรทัด สำหรับแต่ละหลายร้อยล้านบรรทัด ฉันใช้บรรทัดนี้ แยกวิเคราะห์ และโยนมันทิ้งไป ทำไมฉันถึงทิ้งมันไป - ฉันได้ดำเนินการไปแล้วก็แค่นั้นแหละ ดังนั้นสำหรับแต่ละไบต์ที่อ่านจาก 2.7G เหล่านี้อักขระสองตัวจะถูกเขียนในบรรทัดนั่นคือ 5.4G อยู่แล้วและฉันไม่ต้องการสิ่งใดเพิ่มเติมดังนั้นพวกเขาจึงถูกโยนทิ้งไป หากคุณดูที่แบนด์วิธหน่วยความจำ เราจะโหลด 2.7G ที่ส่งผ่านหน่วยความจำและบัสหน่วยความจำในโปรเซสเซอร์ จากนั้นมากกว่าสองเท่าจะถูกส่งไปยังสายที่อยู่ในหน่วยความจำ และทั้งหมดนี้จะหายไปเมื่อมีการสร้างบรรทัดใหม่แต่ละบรรทัด แต่ฉันต้องอ่านมัน ฮาร์ดแวร์ก็อ่านมัน แม้ว่าทุกอย่างจะหลุดลุ่ยในภายหลังก็ตาม และฉันต้องจดบันทึกไว้เพราะฉันสร้างบรรทัดและแคชเต็ม - แคชไม่สามารถรองรับ 2.7G ดังนั้นสำหรับทุกไบต์ที่ฉันอ่าน ฉันจะอ่านเพิ่มอีกสองไบต์และเขียนเพิ่มอีกสองไบต์ และท้ายที่สุดแล้วพวกมันก็มีอัตราส่วน 4:1 - ในอัตราส่วนนี้เราจะสิ้นเปลืองแบนด์วิธหน่วยความจำ แล้วปรากฎว่าถ้าผมทำ String.split() – นี่ไม่ใช่ครั้งสุดท้ายที่ฉันทำสิ่งนี้ ข้างในอาจมีช่องอีก 6-7 ช่อง ดังนั้นโค้ดคลาสสิกในการอ่าน CSV แล้วแยกวิเคราะห์สตริงส่งผลให้แบนด์วิดท์หน่วยความจำสิ้นเปลืองประมาณ 14:1 เมื่อเทียบกับสิ่งที่คุณต้องการจริงๆ หากคุณทิ้งตัวเลือกเหล่านี้ คุณจะได้รับความเร็วเพิ่มขึ้นห้าเท่า

และมันก็ไม่ใช่เรื่องยากขนาดนั้น หากคุณมองโค้ดจากมุมที่ถูกต้อง ทุกอย่างจะค่อนข้างง่ายเมื่อคุณตระหนักถึงปัญหา คุณไม่ควรหยุดการจัดสรรหน่วยความจำโดยสิ้นเชิง ปัญหาเดียวคือคุณจัดสรรบางสิ่งและหน่วยความจำนั้นหยุดทำงานทันที และระหว่างทางหน่วยความจำก็จะเผาผลาญทรัพยากรที่สำคัญ ซึ่งในกรณีนี้คือแบนด์วิดท์หน่วยความจำ และทั้งหมดนี้ส่งผลให้ประสิทธิภาพการทำงานลดลง บน x86 โดยปกติคุณจะต้องเบิร์นรอบโปรเซสเซอร์ แต่ที่นี่คุณเบิร์นหน่วยความจำทั้งหมดเร็วกว่ามาก วิธีแก้ไขคือลดปริมาณการระบายออก 
อีกส่วนหนึ่งของปัญหาคือ หากคุณเรียกใช้ตัวสร้างโปรไฟล์เมื่อแถบหน่วยความจำหมด ทันทีที่มันเกิดขึ้น คุณมักจะรอให้แคชกลับมาเพราะมันเต็มไปด้วยขยะที่คุณเพิ่งสร้างขึ้น ทุกบรรทัดเหล่านั้น ดังนั้นการโหลดหรือการจัดเก็บทุกครั้งจะช้าลงเนื่องจากทำให้เกิดแคชที่หายไป - แคชทั้งหมดช้าลงและรอให้ขยะทิ้งไป ดังนั้นตัวสร้างโปรไฟล์จะแสดงสัญญาณรบกวนแบบสุ่มที่อบอุ่นซึ่งเปื้อนทั่วทั้งลูป - จะไม่มีคำสั่งหรือตำแหน่งร้อนแยกต่างหากในโค้ด มีเสียงรบกวนเท่านั้น และถ้าคุณดูที่วัฏจักร GC พวกมันล้วนเป็นของคนรุ่นใหม่และเร็วมาก - สูงสุดในระดับไมโครวินาทีหรือมิลลิวินาที ท้ายที่สุดแล้ว ความทรงจำทั้งหมดนี้ก็หายไปทันที คุณจัดสรรหลายพันล้านกิกะไบต์ และเขาก็ตัดมัน ตัดมัน แล้วก็ตัดมันอีกครั้ง ทั้งหมดนี้เกิดขึ้นเร็วมาก ปรากฎว่ามีวงจร GC ราคาถูก มีเสียงอุ่นตลอดทั้งวงจร แต่เราอยากได้ความเร็วเพิ่มขึ้น 5 เท่า ในขณะนี้ บางสิ่งบางอย่างน่าจะปิดอยู่ในหัวและมีเสียง: “ทำไมถึงเป็นเช่นนี้!” หน่วยความจำล้นแถบหน่วยความจำจะไม่แสดงในดีบักเกอร์แบบคลาสสิก คุณต้องเรียกใช้ดีบักเกอร์ตัวนับประสิทธิภาพฮาร์ดแวร์และดูด้วยตัวคุณเองโดยตรง แต่ไม่สามารถสงสัยได้โดยตรงจากอาการทั้งสามนี้ อาการที่สามคือเมื่อคุณดูสิ่งที่คุณไฮไลต์ ถามผู้สร้างโปรไฟล์ แล้วเขาก็ตอบว่า “คุณสร้างแถวเป็นพันล้านแถว แต่ GC ใช้งานได้ฟรี” ทันทีที่สิ่งนี้เกิดขึ้น คุณจะพบว่าคุณสร้างวัตถุมากเกินไปและทำให้ช่องความทรงจำเสียหายทั้งหมด มีวิธีคิดออก แต่ก็ไม่ชัดเจน 

ปัญหาอยู่ในโครงสร้างข้อมูล: โครงสร้างเปลือยที่เป็นรากฐานของทุกสิ่งที่เกิดขึ้น มันใหญ่เกินไป มันเป็น 2.7G บนดิสก์ ดังนั้นการทำสำเนาสิ่งนี้จึงไม่พึงปรารถนาอย่างยิ่ง - คุณต้องการโหลดจากบัฟเฟอร์ไบต์เครือข่ายทันที ลงในรีจิสเตอร์เพื่อไม่ให้อ่าน-เขียนบรรทัดไปมาห้าครั้ง น่าเสียดายที่ Java ไม่ได้ให้ไลบรารีดังกล่าวแก่คุณโดยเป็นส่วนหนึ่งของ JDK ตามค่าเริ่มต้น แต่นี่เป็นเรื่องเล็กน้อยใช่ไหม? โดยพื้นฐานแล้ว โค้ดเหล่านี้คือโค้ด 5-10 บรรทัดที่จะใช้เพื่อใช้งานตัวโหลดสตริงที่มีบัฟเฟอร์ของคุณเอง ซึ่งจะทำซ้ำพฤติกรรมของคลาสสตริง ในขณะที่เป็นตัวหุ้มรอบบัฟเฟอร์ไบต์พื้นฐาน ผลปรากฏว่าคุณกำลังทำงานเกือบจะเหมือนกับใช้สตริง แต่ในความเป็นจริงแล้ว ตัวชี้ไปยังบัฟเฟอร์กำลังย้ายไปอยู่ที่นั่น และไบต์ดิบจะไม่ถูกคัดลอกไปที่ใดก็ได้ ดังนั้นบัฟเฟอร์เดิมจึงถูกนำมาใช้ซ้ำแล้วซ้ำเล่า และ ระบบปฏิบัติการยินดีรับมือสิ่งที่ออกแบบมาเพื่อตัวเอง เช่น การซ่อนบัฟเฟอร์ไบต์คู่ของบัฟเฟอร์ไบต์เหล่านี้ และคุณจะไม่ต้องบดขยี้ข้อมูลที่ไม่จำเป็นอีกต่อไป คุณเข้าใจหรือไม่ว่าเมื่อทำงานกับ GC รับประกันได้ว่าการจัดสรรหน่วยความจำแต่ละครั้งจะไม่ปรากฏแก่โปรเซสเซอร์หลังจากรอบ GC สุดท้าย ดังนั้นทั้งหมดนี้ไม่สามารถอยู่ในแคชได้และจากนั้นจะรับประกันการพลาด 100% เมื่อทำงานกับพอยน์เตอร์บน x86 การลบรีจิสเตอร์ออกจากหน่วยความจำจะใช้เวลา 1-2 รอบนาฬิกา และทันทีที่สิ่งนี้เกิดขึ้น คุณจะต้องจ่าย จ่าย จ่าย เพราะหน่วยความจำเปิดอยู่ทั้งหมด เก้าแคช – และนี่คือต้นทุนของการจัดสรรหน่วยความจำ คุณค่าที่แท้จริง

กล่าวอีกนัยหนึ่ง โครงสร้างข้อมูลเป็นสิ่งที่เปลี่ยนแปลงได้ยากที่สุด และเมื่อคุณตระหนักว่าคุณได้เลือกโครงสร้างข้อมูลผิดที่จะลดประสิทธิภาพในภายหลัง มักจะมีงานที่ต้องทำอีกมาก แต่ถ้าคุณไม่ทำ สิ่งต่างๆ จะแย่ลง ก่อนอื่น คุณต้องคิดถึงโครงสร้างข้อมูลก่อน นี่เป็นสิ่งสำคัญ ค่าใช้จ่ายหลักที่นี่ตกอยู่ที่โครงสร้างข้อมูลไขมัน ซึ่งเริ่มมีการใช้ในรูปแบบ "ฉันคัดลอกโครงสร้างข้อมูล X ลงในโครงสร้างข้อมูล Y เพราะฉันชอบรูปร่างของ Y มากกว่า" แต่การดำเนินการคัดลอก (ซึ่งดูเหมือนว่าราคาถูก) จะทำให้แบนด์วิธหน่วยความจำสิ้นเปลืองจริง และนั่นคือจุดที่เวลาดำเนินการที่สูญเปล่าทั้งหมดถูกฝังไว้ ถ้าฉันมีสตริง JSON ขนาดยักษ์ และฉันต้องการเปลี่ยนให้เป็นโครงสร้าง DOM tree ของ POJO หรืออะไรสักอย่าง การดำเนินการแยกวิเคราะห์สตริงนั้นและสร้าง POJO จากนั้นเข้าถึง POJO อีกครั้งในภายหลัง จะส่งผลให้เกิดค่าใช้จ่ายที่ไม่จำเป็น - ไม่ถูก. ยกเว้นในกรณีที่คุณวิ่งวนรอบ POJO บ่อยกว่าวิ่งวนรอบสตริงมาก ทันที คุณสามารถลองถอดรหัสสตริงและแยกเฉพาะสิ่งที่คุณต้องการจากที่นั่นแทน โดยไม่ต้องเปลี่ยนเป็น POJO ใดๆ หากทั้งหมดนี้เกิดขึ้นบนเส้นทางที่ต้องการประสิทธิภาพสูงสุด ไม่มี POJO สำหรับคุณ คุณจะต้องเจาะลึกเข้าไปในบรรทัดโดยตรง

ทำไมต้องสร้างภาษาโปรแกรมของคุณเอง

แอนดรู: คุณบอกว่าจะเข้าใจ cost model ต้องเขียนภาษาเล็กๆ น้อยๆ ของคุณเอง...

หน้าผา: ไม่ใช่ภาษา แต่เป็นคอมไพเลอร์ ภาษาและคอมไพเลอร์เป็นสองสิ่งที่แตกต่างกัน ความแตกต่างที่สำคัญที่สุดอยู่ในหัวของคุณ 

แอนดรู: อย่างไรก็ตาม เท่าที่ฉันรู้ คุณกำลังทดลองสร้างภาษาของคุณเอง เพื่ออะไร?

หน้าผา: เพราะฉันทำได้! ฉันกึ่งเกษียณแล้ว นี่คืองานอดิเรกของฉัน ฉันใช้ภาษาของคนอื่นมาตลอดชีวิต ฉันยังทำงานมากกับสไตล์การเขียนโค้ดของฉันด้วย และเพราะฉันเห็นปัญหาในภาษาอื่นด้วย ฉันเห็นว่ามีวิธีที่ดีกว่าในการทำสิ่งที่คุ้นเคย และฉันจะใช้มัน ฉันแค่เบื่อที่จะเห็นปัญหาในตัวฉัน ใน Java ใน Python หรือภาษาอื่น ๆ ตอนนี้ฉันเขียนด้วย React Native, JavaScript และ Elm เพื่อเป็นงานอดิเรกที่ไม่เกี่ยวกับการเกษียณอายุ แต่เกี่ยวกับการทำงานที่กระตือรือร้น ฉันยังเขียนด้วยภาษา Python และมีแนวโน้มว่าจะยังคงทำงานเกี่ยวกับการเรียนรู้ของเครื่องสำหรับแบ็กเอนด์ Java ต่อไป มีภาษายอดนิยมมากมายและทุกภาษาก็มีคุณสมบัติที่น่าสนใจ ทุกคนต่างก็เก่งในแบบของตัวเอง และคุณสามารถลองนำคุณสมบัติเหล่านี้มารวมกันได้ ฉันกำลังศึกษาสิ่งต่างๆ ที่ฉันสนใจ พฤติกรรมของภาษา พยายามหาความหมายที่สมเหตุสมผล และจนถึงตอนนี้ฉันก็ทำสำเร็จแล้ว! ในขณะนี้ ฉันกำลังดิ้นรนกับซีแมนทิกส์หน่วยความจำ เพราะฉันต้องการให้มีเหมือนใน C และ Java และรับโมเดลหน่วยความจำที่แข็งแกร่งและซีแมนทิกส์หน่วยความจำสำหรับการโหลดและการจัดเก็บ ขณะเดียวกันก็มีการอนุมานประเภทอัตโนมัติเหมือนใน Haskell ที่นี่ ฉันกำลังพยายามผสมการอนุมานแบบ Haskell เข้ากับงานหน่วยความจำทั้งใน C และ Java นี่คือสิ่งที่ฉันทำในช่วง 2-3 เดือนที่ผ่านมาเป็นต้น

แอนดรู: หากคุณสร้างภาษาที่คำนึงถึงแง่มุมที่ดีกว่าจากภาษาอื่น คุณคิดว่าจะมีคนทำตรงกันข้ามหรือไม่: นำความคิดของคุณไปใช้

หน้าผา: นี่คือลักษณะที่ภาษาใหม่ปรากฏขึ้น! ทำไม Java ถึงคล้ายกับ C? เนื่องจาก C มีไวยากรณ์ที่ดีที่ทุกคนเข้าใจ และ Java ก็ได้รับแรงบันดาลใจจากไวยากรณ์นี้ เพิ่มความปลอดภัยประเภท การตรวจสอบขอบเขตของอาร์เรย์ GC และพวกเขายังปรับปรุงบางสิ่งจาก C พวกเขาเพิ่มของตัวเองเข้าไปด้วย แต่พวกเขาก็ได้รับแรงบันดาลใจค่อนข้างมากใช่ไหม? ทุกคนยืนอยู่บนไหล่ของยักษ์ใหญ่ที่อยู่ตรงหน้าคุณ - นั่นคือความก้าวหน้า

แอนดรู: ตามที่ฉันเข้าใจ ภาษาของคุณจะปลอดภัยในความทรงจำ คุณเคยคิดที่จะดำเนินการบางอย่างเช่นตัวตรวจสอบการยืมจาก Rust หรือไม่? คุณเคยมองเขาแล้วคุณคิดอย่างไรกับเขา?

หน้าผา: ฉันเขียน C มาหลายปีแล้ว ด้วย malloc ทั้งหมดนี้ฟรี และจัดการอายุการใช้งานด้วยตนเอง คุณรู้ไหมว่า 90-95% ของอายุการใช้งานที่ควบคุมด้วยตนเองมีโครงสร้างเดียวกัน และมันเจ็บปวดมากที่จะทำด้วยตนเอง ฉันต้องการให้คอมไพเลอร์บอกคุณว่าเกิดอะไรขึ้นและคุณทำอะไรได้บ้างจากการกระทำของคุณ สำหรับบางสิ่ง ตัวตรวจสอบการยืมจะทำสิ่งนี้ทันที และควรแสดงข้อมูลโดยอัตโนมัติ เข้าใจทุกอย่าง และไม่ทำให้ฉันเป็นภาระในการนำเสนอความเข้าใจนี้ด้วยซ้ำ อย่างน้อยที่สุดจะต้องทำการวิเคราะห์ Escape ในเครื่อง และเฉพาะในกรณีที่ล้มเหลว จะต้องเพิ่มคำอธิบายประกอบประเภทที่จะอธิบายอายุการใช้งาน - และรูปแบบดังกล่าวซับซ้อนกว่าตัวตรวจสอบการยืมหรือตัวตรวจสอบหน่วยความจำที่มีอยู่จริงๆ ทางเลือกระหว่าง "ทุกอย่างเรียบร้อยดี" และ "ฉันไม่เข้าใจอะไรเลย" - ไม่ ต้องมีบางอย่างที่ดีกว่านี้แน่ 
ดังนั้นในฐานะคนที่เขียนโค้ดในภาษา C เป็นจำนวนมาก ฉันคิดว่าการรองรับการควบคุมอายุการใช้งานแบบอัตโนมัติเป็นสิ่งสำคัญที่สุด ฉันยังรู้สึกเบื่อหน่ายกับปริมาณการใช้หน่วยความจำของ Java และข้อร้องเรียนหลักคือ GC เมื่อคุณจัดสรรหน่วยความจำใน Java คุณจะไม่ได้รับหน่วยความจำที่อยู่ในเครื่องกลับคืนมาในรอบ GC ล่าสุด นี่ไม่ใช่กรณีในภาษาที่มีการจัดการหน่วยความจำที่แม่นยำยิ่งขึ้น หากคุณเรียก malloc คุณจะได้รับหน่วยความจำที่ปกติเพิ่งใช้ทันที โดยปกติแล้วคุณจะทำสิ่งชั่วคราวด้วยหน่วยความจำแล้วคืนกลับทันที และมันจะกลับไปที่พูล malloc ทันที และรอบ malloc ถัดไปจะดึงมันออกมาอีกครั้ง ดังนั้นการใช้งานหน่วยความจำจริงจึงลดลงเหลือชุดของสิ่งมีชีวิต ณ เวลาที่กำหนด บวกกับการรั่วไหล และหากทุกอย่างไม่รั่วไหลในลักษณะที่ไม่เหมาะสมเลย หน่วยความจำส่วนใหญ่จะไปอยู่ในแคชและโปรเซสเซอร์ และทำงานได้อย่างรวดเร็ว แต่ต้องการการจัดการหน่วยความจำแบบแมนนวลจำนวนมากด้วย malloc และการเรียกใช้ฟรีตามลำดับที่ถูกต้อง ในตำแหน่งที่ถูกต้อง Rust สามารถจัดการสิ่งนี้ได้อย่างเหมาะสมด้วยตัวเอง และในหลายกรณีก็ให้ประสิทธิภาพที่ดียิ่งขึ้น เนื่องจากการใช้หน่วยความจำถูกจำกัดให้แคบลงเหลือเพียงการคำนวณปัจจุบัน แทนที่จะรอรอบ GC ถัดไปเพื่อเพิ่มหน่วยความจำ ด้วยเหตุนี้ เราจึงมีวิธีที่น่าสนใจมากในการปรับปรุงประสิทธิภาพ และค่อนข้างทรงพลัง - ฉันหมายถึง ฉันทำสิ่งต่าง ๆ เมื่อประมวลผลข้อมูลสำหรับฟินเทค และสิ่งนี้ทำให้ฉันเร่งความเร็วได้ประมาณห้าเท่า นั่นเป็นการเพิ่มขึ้นอย่างมาก โดยเฉพาะอย่างยิ่งในโลกที่โปรเซสเซอร์ไม่ได้ทำงานเร็วขึ้น และเรายังคงรอการปรับปรุงอยู่

อาชีพวิศวกรประสิทธิภาพ

แอนดรู: ฉันอยากจะถามเกี่ยวกับอาชีพโดยทั่วไปด้วย คุณมีความโดดเด่นจากงาน JIT ของคุณที่ HotSpot จากนั้นจึงย้ายไปที่ Azul ซึ่งเป็นบริษัท JVM เช่นกัน แต่เราทำงานด้านฮาร์ดแวร์มากกว่าซอฟต์แวร์อยู่แล้ว จากนั้นพวกเขาก็เปลี่ยนมาใช้ Big Data และ Machine Learning ทันที จากนั้นจึงเปลี่ยนเป็นการตรวจจับการฉ้อโกง มันเกิดขึ้นได้อย่างไร? สิ่งเหล่านี้เป็นขอบเขตการพัฒนาที่แตกต่างกันมาก

หน้าผา: ฉันเขียนโปรแกรมมาค่อนข้างนานและได้เข้าเรียนในชั้นเรียนต่างๆ มากมาย และเมื่อมีคนพูดว่า: "โอ้ คุณเป็นคนที่ทำ JIT สำหรับ Java!" มันก็ตลกเสมอ แต่ก่อนหน้านั้น ฉันกำลังสร้างโคลนของ PostScript ซึ่งเป็นภาษาที่ Apple เคยใช้กับเครื่องพิมพ์เลเซอร์ และก่อนหน้านั้นฉันได้นำภาษาที่สี่ไปใช้ ฉันคิดว่าธีมทั่วไปสำหรับฉันคือการพัฒนาเครื่องมือ ตลอดชีวิตของฉันฉันสร้างเครื่องมือเพื่อให้คนอื่นเขียนโปรแกรมเจ๋งๆ ของพวกเขา แต่ฉันยังมีส่วนร่วมในการพัฒนาระบบปฏิบัติการ, ไดรเวอร์, ดีบักเกอร์ระดับเคอร์เนล, ภาษาสำหรับการพัฒนาระบบปฏิบัติการซึ่งเริ่มต้นจากเรื่องเล็กน้อย แต่เมื่อเวลาผ่านไปก็ซับซ้อนมากขึ้นเรื่อย ๆ แต่หัวข้อหลักยังคงเป็นการพัฒนาเครื่องมือ ชีวิตส่วนใหญ่ของฉันอยู่ระหว่าง Azul และ Sun และมันเป็นเรื่องของ Java แต่เมื่อฉันเข้าสู่ Big Data และ Machine Learning ฉันก็สวมหมวกแฟนซีกลับคืนมาและพูดว่า "โอ้ ตอนนี้เรามีปัญหาเล็กๆ น้อยๆ แล้ว และยังมีเรื่องน่าสนใจมากมายเกิดขึ้นและผู้คนก็กำลังทำสิ่งต่างๆ อยู่" นี่เป็นเส้นทางการพัฒนาที่ยอดเยี่ยม

ใช่ ฉันชอบการประมวลผลแบบกระจายมาก งานแรกของฉันคือเป็นนักเรียนใน C ในโครงการโฆษณา ข้อมูลนี้กระจายการประมวลผลบนชิป Zilog Z80 ซึ่งรวบรวมข้อมูลสำหรับ OCR แบบอะนาล็อก ซึ่งผลิตโดยเครื่องวิเคราะห์แบบอะนาล็อกจริง มันเป็นหัวข้อที่เจ๋งและบ้าบอมาก แต่มีปัญหาบางส่วนไม่สามารถรับรู้ได้ถูกต้องจึงต้องนำภาพออกมาแสดงให้คนที่สามารถอ่านด้วยตาแล้วรายงานสิ่งที่พูดจึงมีงานที่มีข้อมูลและงานเหล่านี้ มีภาษาของตัวเอง มีแบ็กเอนด์ที่ประมวลผลทั้งหมดนี้ - Z80 ทำงานแบบขนานกับเทอร์มินัล vt100 ทำงาน - หนึ่งรายการต่อคน และมีโมเดลการเขียนโปรแกรมแบบขนานบน Z80 หน่วยความจำทั่วไปบางส่วนที่ใช้ร่วมกันโดย Z80 ทั้งหมดภายในการกำหนดค่าแบบดาว แบ็คเพลนยังถูกแชร์ และ RAM ครึ่งหนึ่งถูกแชร์ภายในเครือข่าย และอีกครึ่งหนึ่งเป็นแบบส่วนตัวหรือไปที่อย่างอื่น ระบบกระจายแบบขนานที่ซับซ้อนอย่างมีความหมายพร้อมการแบ่งใช้... หน่วยความจำแบบกึ่งแบ่งใช้ เมื่อไหร่กัน... ฉันจำไม่ได้ด้วยซ้ำ ที่ไหนสักแห่งในช่วงกลางยุค 80 ค่อนข้างนานมาแล้ว 
ใช่ สมมุติว่า 30 ปีที่แล้วค่อนข้างนานมาแล้ว ปัญหาเกี่ยวกับ Distributed Computing มีมานานแล้ว ผู้คนทำสงครามกับ วูล์ฟ-คลัสเตอร์ คลัสเตอร์ดังกล่าวมีลักษณะดังนี้... ตัวอย่างเช่น: มีอีเทอร์เน็ตและ x86 ที่รวดเร็วของคุณเชื่อมต่อกับอีเทอร์เน็ตนี้ และตอนนี้คุณต้องการได้รับหน่วยความจำที่ใช้ร่วมกันปลอม เนื่องจากไม่มีใครสามารถทำการเข้ารหัสการคำนวณแบบกระจายได้ จึงยากเกินไปดังนั้นจึงมี เป็นหน่วยความจำที่ใช้ร่วมกันปลอมที่มีหน้าหน่วยความจำป้องกันบน x86 และหากคุณเขียนถึงหน้านี้ เราก็บอกโปรเซสเซอร์อื่น ๆ ว่าหากพวกเขาเข้าถึงหน่วยความจำที่ใช้ร่วมกันเดียวกัน จะต้องโหลดจากคุณ และด้วยเหตุนี้จึงมีบางอย่างที่เหมือนกับโปรโตคอลสำหรับการสนับสนุน การเชื่อมโยงกันของแคชปรากฏขึ้นและซอฟต์แวร์สำหรับสิ่งนี้ แนวคิดที่น่าสนใจ แน่นอนว่าปัญหาที่แท้จริงคืออย่างอื่น ทั้งหมดนี้ได้ผล แต่คุณประสบปัญหาด้านประสิทธิภาพอย่างรวดเร็ว เนื่องจากไม่มีใครเข้าใจโมเดลประสิทธิภาพในระดับที่ดีเพียงพอ - มีรูปแบบการเข้าถึงหน่วยความจำแบบใด วิธีตรวจสอบให้แน่ใจว่าโหนดไม่ส่ง Ping ซึ่งกันและกันอย่างไม่มีที่สิ้นสุด เป็นต้น

สิ่งที่ฉันคิดขึ้นมาใน H2O ก็คือนักพัฒนาเองที่มีหน้าที่รับผิดชอบในการพิจารณาว่าความเท่าเทียมซ่อนอยู่ที่ไหนและอยู่ที่ไหน ฉันคิดรูปแบบการเขียนโค้ดที่ทำให้การเขียนโค้ดประสิทธิภาพสูงเป็นเรื่องง่ายและเรียบง่าย แต่การเขียนโค้ดที่รันช้านั้นทำได้ยากมันจะดูแย่ คุณต้องพยายามเขียนโค้ดที่ช้าอย่างจริงจัง คุณจะต้องใช้วิธีการที่ไม่ได้มาตรฐาน รหัสเบรกสามารถมองเห็นได้ในพริบตา เป็นผลให้คุณมักจะเขียนโค้ดที่ทำงานเร็ว แต่คุณต้องค้นหาว่าต้องทำอย่างไรในกรณีของหน่วยความจำที่ใช้ร่วมกัน ทั้งหมดนี้เชื่อมโยงกับอาร์เรย์ขนาดใหญ่และลักษณะการทำงานจะคล้ายกับอาร์เรย์ขนาดใหญ่ที่ไม่ลบเลือนใน Java แบบขนาน ฉันหมายถึง ลองจินตนาการว่าสองเธรดเขียนไปยังอาร์เรย์คู่ขนาน หนึ่งในนั้นชนะ และอีกเธรดหนึ่งจึงสูญเสีย และคุณไม่รู้ว่าเธรดไหนเป็นเธรดไหน หากพวกมันไม่ผันผวน คำสั่งซื้ออาจเป็นอะไรก็ได้ที่คุณต้องการ - และวิธีนี้ใช้ได้ผลดีจริงๆ ผู้คนให้ความสำคัญกับลำดับการปฏิบัติงาน พวกเขาวางความผันผวนในตำแหน่งที่ถูกต้อง และพวกเขาคาดหวังว่าปัญหาด้านประสิทธิภาพที่เกี่ยวข้องกับหน่วยความจำจะอยู่ในตำแหน่งที่ถูกต้อง มิฉะนั้น พวกเขาก็จะเขียนโค้ดในรูปแบบของลูปตั้งแต่ 1 ถึง N โดยที่ N คือล้านล้าน ด้วยความหวังว่ากรณีที่ซับซ้อนทั้งหมดจะกลายเป็นแบบขนานโดยอัตโนมัติ และมันจะไม่ทำงานที่นั่น แต่ใน H2O นี่ไม่ใช่ทั้ง Java และ Scala คุณสามารถพิจารณาว่าเป็น "Java ลบลบ" ได้หากต้องการ นี่เป็นรูปแบบการเขียนโปรแกรมที่ชัดเจนมากและคล้ายกับการเขียนโค้ด C หรือ Java แบบธรรมดาที่มีลูปและอาร์เรย์ แต่ในขณะเดียวกัน หน่วยความจำก็สามารถประมวลผลได้ในหน่วยเทราไบต์ ฉันยังคงใช้ H2O ฉันใช้มันเป็นครั้งคราวในโครงการต่างๆ - และยังคงเป็นสิ่งที่เร็วที่สุด เร็วกว่าคู่แข่งหลายสิบเท่า หากคุณกำลังทำ Big Data ด้วยข้อมูลแบบเรียงเป็นแนว เป็นเรื่องยากมากที่จะเอาชนะ H2O

ความท้าทายทางเทคนิค

แอนดรู: อะไรคือความท้าทายที่ยิ่งใหญ่ที่สุดตลอดอาชีพการงานของคุณ?

หน้าผา: เรากำลังคุยเรื่องทางเทคนิคหรือไม่ใช่ด้านเทคนิคของปัญหานี้หรือไม่ ฉันจะบอกว่าความท้าทายที่ยิ่งใหญ่ที่สุดไม่ใช่ความท้าทายทางเทคนิค 
สำหรับความท้าทายทางเทคนิค ฉันเพียงแค่เอาชนะพวกเขา ฉันไม่รู้ด้วยซ้ำว่าอะไรที่ใหญ่ที่สุด แต่มีบางอันที่น่าสนใจทีเดียว ซึ่งใช้เวลานานพอสมควร ก็คือการต่อสู้ทางจิต เมื่อฉันไปเรียนที่ Sun ฉันแน่ใจว่าฉันจะสร้างคอมไพเลอร์ที่รวดเร็วได้ และผู้อาวุโสกลุ่มหนึ่งก็ตอบไปว่าฉันจะไม่ประสบความสำเร็จ แต่ฉันทำตามเส้นทางนี้ เขียนคอมไพเลอร์ลงในตัวจัดสรรการลงทะเบียน และมันก็ค่อนข้างเร็ว มันเร็วพอๆ กับ C1 สมัยใหม่ แต่ตัวจัดสรรนั้นช้ากว่ามากในตอนนั้น และเมื่อมองย้อนกลับไปแล้ว มันเป็นปัญหาโครงสร้างข้อมูลขนาดใหญ่ ฉันต้องการให้เขียนตัวจัดสรรการลงทะเบียนแบบกราฟิก และฉันไม่เข้าใจภาวะที่กลืนไม่เข้าคายไม่ออกระหว่างความหมายของโค้ดและความเร็ว ซึ่งมีอยู่ในยุคนั้นและมีความสำคัญมาก ปรากฎว่าโครงสร้างข้อมูลมักจะเกินขนาดแคชใน x86 ในเวลานั้นดังนั้นหากในตอนแรกฉันคิดว่าตัวจัดสรรการลงทะเบียนจะทำงานได้ 5-10 เปอร์เซ็นต์ของเวลากระวนกระวายใจทั้งหมดจากนั้นในความเป็นจริงมันกลับกลายเป็นว่า 50 เปอร์เซ็นต์

เมื่อเวลาผ่านไป คอมไพลเลอร์ก็สะอาดขึ้นและมีประสิทธิภาพมากขึ้น หยุดสร้างโค้ดที่แย่ในหลาย ๆ กรณี และประสิทธิภาพก็เริ่มคล้ายกับสิ่งที่คอมไพเลอร์ C ผลิตมากขึ้น เว้นแต่ว่าคุณจะเขียนเรื่องไร้สาระที่แม้แต่ C ก็ไม่เร่งความเร็วขึ้น . หากคุณเขียนโค้ดเช่น C คุณจะได้รับประสิทธิภาพเช่น C ในหลาย ๆ กรณี และยิ่งคุณไปไกลเท่าไร คุณก็ยิ่งได้รับโค้ดที่ใกล้เคียงกับระดับ C มากขึ้นเท่านั้น ตัวจัดสรรการลงทะเบียนก็เริ่มดูเหมือนมีบางอย่างที่สมบูรณ์... ไม่ว่าโค้ดของคุณจะทำงานเร็วหรือช้าก็ตาม ฉันยังคงทำงานกับตัวจัดสรรต่อไปเพื่อให้ทำการเลือกได้ดีขึ้น เขาช้าลงเรื่อยๆ แต่เขาให้ประสิทธิภาพที่ดีขึ้นเรื่อยๆ ในกรณีที่ไม่มีใครสามารถรับมือได้ ฉันสามารถดำดิ่งลงไปในตัวจัดสรรการลงทะเบียน ฝังงานหนึ่งเดือนที่นั่น และทันใดนั้นโค้ดทั้งหมดก็เริ่มดำเนินการเร็วขึ้น 5% สิ่งนี้เกิดขึ้นครั้งแล้วครั้งเล่าและผู้จัดสรรการลงทะเบียนกลายเป็นงานศิลปะ - ทุกคนชอบหรือเกลียดมัน และผู้คนจากสถาบันการศึกษาก็ถามคำถามในหัวข้อ "ทำไมทุกอย่างถึงทำเช่นนี้" ทำไมไม่ สแกนเส้นและอะไรคือความแตกต่าง คำตอบยังคงเหมือนเดิม: ตัวจัดสรรตามการระบายสีกราฟบวกกับการทำงานอย่างระมัดระวังกับโค้ดบัฟเฟอร์นั้นเท่ากับอาวุธแห่งชัยชนะ ซึ่งเป็นการผสมผสานที่ดีที่สุดที่ไม่มีใครสามารถเอาชนะได้ และนี่เป็นสิ่งที่ค่อนข้างไม่ชัดเจน ทุกสิ่งทุกอย่างที่คอมไพเลอร์ทำนั้นล้วนแต่ได้รับการศึกษามาเป็นอย่างดี แม้ว่าสิ่งเหล่านั้นจะถูกพัฒนาไปสู่ระดับศิลปะก็ตาม ฉันมักจะทำสิ่งที่ควรจะเปลี่ยนผู้เรียบเรียงให้เป็นงานศิลปะอยู่เสมอ แต่สิ่งนี้ไม่ได้มีอะไรพิเศษเลย ยกเว้นผู้จัดสรรทะเบียน เคล็ดลับคือการระมัดระวัง ตัดลง ภายใต้ภาระงานและหากสิ่งนี้เกิดขึ้น (ฉันสามารถอธิบายรายละเอียดเพิ่มเติมได้หากสนใจ) ซึ่งหมายความว่าคุณสามารถอินไลน์ได้อย่างดุดันมากขึ้น โดยไม่มีความเสี่ยงที่จะล้มทับตารางการแสดง ในสมัยนั้น มีคอมไพเลอร์เต็มรูปแบบจำนวนหนึ่งที่แขวนประดับด้วยต่างหูและนกหวีด ซึ่งมีตัวจัดสรรการลงทะเบียน แต่ไม่มีใครสามารถทำได้

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

เล็กน้อยเกี่ยวกับการจัดสรรการลงทะเบียนและมัลติคอร์

วลาดิเมีย: ปัญหาเช่นการจัดสรรการลงทะเบียนดูเหมือนเป็นหัวข้อนิรันดร์และไม่มีที่สิ้นสุด ฉันสงสัยว่าเคยมีแนวคิดใดที่ดูเหมือนมีแนวโน้มดีแต่กลับล้มเหลวในทางปฏิบัติหรือไม่?

หน้าผา: แน่นอน! การจัดสรรการลงทะเบียนเป็นพื้นที่ที่คุณพยายามค้นหาการวิเคราะห์พฤติกรรมบางอย่างเพื่อแก้ไขปัญหา NP ที่สมบูรณ์ และคุณไม่สามารถบรรลุวิธีแก้ปัญหาที่สมบูรณ์แบบได้ใช่ไหม นี่เป็นไปไม่ได้เลย ดูสิ การรวบรวมล่วงหน้า - มันทำงานได้ไม่ดีเช่นกัน บทสนทนานี้เป็นเรื่องเกี่ยวกับกรณีทั่วไปบางกรณี เกี่ยวกับประสิทธิภาพโดยทั่วไป ดังนั้นคุณจึงสามารถไปวัดสิ่งที่คุณคิดว่าเป็นประสิทธิภาพโดยทั่วไปที่ดีได้ เพราะท้ายที่สุดแล้ว คุณกำลังพยายามปรับปรุงมัน! การจัดสรรการลงทะเบียนเป็นหัวข้อเกี่ยวกับประสิทธิภาพ เมื่อคุณมีต้นแบบแรกแล้ว มันก็ใช้งานได้และลงสีตามที่จำเป็น งานด้านประสิทธิภาพก็เริ่มต้นขึ้น คุณต้องเรียนรู้ที่จะวัดให้ดี ทำไมมันถึงสำคัญ? หากคุณมีข้อมูลที่ชัดเจน คุณสามารถดูส่วนต่างๆ และดูได้ ใช่ มันช่วยได้ที่นี่ แต่นั่นคือจุดที่ทุกอย่างพัง! ไอเดียดีๆ บางอย่างเกิดขึ้น คุณเพิ่มการวิเคราะห์พฤติกรรมใหม่ๆ และทันใดนั้นทุกอย่างก็เริ่มทำงานดีขึ้นโดยเฉลี่ยเล็กน้อย หรือมันสตาร์ทไม่ติด ฉันมีหลายๆ กรณีที่เราต่อสู้เพื่อประสิทธิภาพห้าเปอร์เซ็นต์ที่ทำให้การพัฒนาของเราแตกต่างจากตัวจัดสรรครั้งก่อน และทุกครั้งมันก็เป็นแบบนี้: ที่ไหนสักแห่งที่คุณชนะ ที่ไหนสักแห่งที่คุณแพ้ หากคุณมีเครื่องมือวิเคราะห์ประสิทธิภาพที่ดี คุณสามารถค้นหาแนวคิดที่เสียไปและเข้าใจสาเหตุที่ล้มเหลวได้ บางทีมันอาจจะคุ้มค่าที่จะทิ้งทุกอย่างไว้เหมือนเดิม หรืออาจใช้แนวทางที่จริงจังกว่านี้ในการปรับแต่ง หรือออกไปแก้ไขอย่างอื่น เป็นของแถมเพียบ! ฉันทำแฮ็คสุดเจ๋งนี้ แต่ฉันก็ต้องการอันนี้ และอันนี้ และอันนี้ด้วย - และการรวมกันทั้งหมดทำให้มีการปรับปรุงบางอย่าง และผู้โดดเดี่ยวสามารถล้มเหลวได้ นี่คือลักษณะของการทำงานด้านประสิทธิภาพกับปัญหา NP-complete

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

หน้าผา: มันไม่ได้รับการแก้ไขเช่นนั้น คุณคือคนที่จะต้องทำให้มันกลายเป็น "แก้ไข" มีปัญหาที่ยากลำบากและจำเป็นต้องแก้ไข เมื่อเสร็จแล้วก็ถึงเวลาเพิ่มผลผลิต คุณต้องดำเนินการงานนี้ให้สอดคล้องกัน - ทำการวัดประสิทธิภาพ รวบรวมตัวชี้วัด อธิบายสถานการณ์ที่เมื่อคุณย้อนกลับไปใช้เวอร์ชันก่อนหน้า แฮ็คเก่าของคุณเริ่มทำงานอีกครั้ง (หรือกลับกัน หยุดทำงาน) และอย่ายอมแพ้จนกว่าคุณจะบรรลุบางสิ่งบางอย่าง ดังที่ฉันได้กล่าวไปแล้วหากมีแนวคิดเจ๋ง ๆ ที่ไม่ได้ผล แต่ในด้านของการจัดสรรการลงทะเบียนความคิดก็จะไม่มีที่สิ้นสุด ตัวอย่างเช่น คุณสามารถอ่านสิ่งพิมพ์ทางวิทยาศาสตร์ได้ แม้ว่าตอนนี้บริเวณนี้จะเริ่มเคลื่อนไหวช้ากว่ามากและมีความชัดเจนมากกว่าในวัยเยาว์ก็ตาม อย่างไรก็ตาม มีคนจำนวนนับไม่ถ้วนที่ทำงานในสาขานี้ และความคิดทั้งหมดของพวกเขาก็คุ้มค่าที่จะลอง พวกเขาทุกคนกำลังรออยู่ในปีก และคุณไม่สามารถบอกได้ว่ามันดีแค่ไหนเว้นแต่คุณจะลอง พวกมันรวมเข้ากับทุกสิ่งในตัวจัดสรรของคุณได้ดีแค่ไหน เนื่องจากตัวจัดสรรทำหลายอย่าง และแนวคิดบางอย่างอาจไม่ทำงานในตัวจัดสรรเฉพาะของคุณ แต่ในตัวจัดสรรอื่น พวกมันจะทำงานได้อย่างง่ายดาย วิธีหลักในการชนะสำหรับผู้จัดสรรคือการดึงสิ่งที่ช้าออกไปนอกเส้นทางหลักและบังคับให้แยกไปตามขอบเขตของเส้นทางที่ช้า ดังนั้น หากคุณต้องการเรียกใช้ GC ให้ใช้เส้นทางที่ช้า เพิ่มประสิทธิภาพ ทิ้งข้อยกเว้น ทั้งหมดนี้ คุณรู้ว่าสิ่งเหล่านี้ค่อนข้างหายาก และพวกมันหายากมาก ฉันตรวจสอบแล้ว คุณทำงานพิเศษและขจัดข้อจำกัดมากมายบนเส้นทางที่ช้าเหล่านี้ แต่ก็ไม่ได้สำคัญอะไรนักเพราะมันช้าและไม่ค่อยมีการเดินทาง ตัวอย่างเช่น ตัวชี้ว่าง - มันไม่เคยเกิดขึ้นใช่ไหม? คุณต้องมีหลายเส้นทางสำหรับสิ่งต่าง ๆ แต่ไม่ควรรบกวนเส้นทางหลัก 

วลาดิเมีย: คุณคิดอย่างไรเกี่ยวกับ Multi-Core ในเมื่อมีหลายพัน Core ในคราวเดียว? นี่เป็นสิ่งที่มีประโยชน์หรือไม่?

หน้าผา: ความสำเร็จของ GPU แสดงให้เห็นว่ามีประโยชน์มากทีเดียว!

วลาดิเมีย: พวกเขาค่อนข้างเชี่ยวชาญ แล้วโปรเซสเซอร์อเนกประสงค์ล่ะ?

หน้าผา: นั่นคือโมเดลธุรกิจของ Azul คำตอบกลับมาในยุคที่ผู้คนชื่นชอบประสิทธิภาพที่คาดเดาได้จริงๆ สมัยนั้นเขียนโค้ดคู่ขนานได้ยาก โมเดลการเข้ารหัส H2O สามารถปรับขนาดได้สูง แต่ไม่ใช่โมเดลที่มีจุดประสงค์ทั่วไป อาจจะกว้างกว่าเมื่อใช้ GPU เล็กน้อย เรากำลังพูดถึงความซับซ้อนในการพัฒนาสิ่งนั้นหรือความซับซ้อนของการใช้มัน? ตัวอย่างเช่น Azul สอนบทเรียนที่น่าสนใจให้ฉัน ซึ่งเป็นบทเรียนที่ค่อนข้างไม่ชัดเจน: แคชขนาดเล็กเป็นเรื่องปกติ 

ความท้าทายที่ยิ่งใหญ่ที่สุดในชีวิต

วลาดิเมีย: แล้วความท้าทายที่ไม่ใช่ด้านเทคนิคล่ะ?

หน้าผา: ความท้าทายที่ใหญ่ที่สุดไม่ใช่การ... ใจดีและดีต่อผู้คน และด้วยเหตุนี้ ฉันจึงพบว่าตัวเองตกอยู่ในสถานการณ์ที่ขัดแย้งกันอย่างรุนแรงอยู่ตลอดเวลา คนที่ฉันรู้ว่ามีสิ่งผิดปกติเกิดขึ้น แต่ไม่รู้ว่าจะก้าวไปข้างหน้ากับปัญหาเหล่านั้นอย่างไรและไม่สามารถจัดการได้ ปัญหาระยะยาวมากมายที่ยืดเยื้อมานานหลายสิบปีก็เกิดขึ้นเช่นนี้ ความจริงที่ว่า Java มีคอมไพเลอร์ C1 และ C2 เป็นผลโดยตรงจากสิ่งนี้ ความจริงที่ว่าไม่มีการคอมไพล์หลายระดับใน Java เป็นเวลาสิบปีติดต่อกันก็เป็นผลโดยตรงเช่นกัน เห็นได้ชัดว่าเราต้องการระบบดังกล่าว แต่ก็ไม่ชัดเจนว่าเหตุใดจึงไม่มีอยู่จริง ฉันมีปัญหากับวิศวกรคนหนึ่ง... หรือกลุ่มวิศวกร กาลครั้งหนึ่งเมื่อฉันเริ่มทำงานที่ Sun ฉัน... โอเค ไม่ใช่แค่ตอนนั้น ฉันมักจะมีความคิดเห็นของตัวเองในทุกเรื่องเสมอ และฉันคิดว่ามันเป็นเรื่องจริงที่คุณสามารถเอาความจริงนี้ของคุณและบอกมันตรงๆ โดยเฉพาะอย่างยิ่งเมื่อฉันตกใจเกือบตลอดเวลา และถ้าคุณไม่ชอบแนวทางนี้... โดยเฉพาะอย่างยิ่งถ้าคุณทำผิดอย่างเห็นได้ชัดและทำเรื่องไร้สาระ... โดยทั่วไปแล้ว มีน้อยคนนักที่จะยอมรับการสื่อสารรูปแบบนี้ แม้ว่าบางคนอาจชอบฉันก็ตาม ฉันสร้างมาทั้งชีวิตบนหลักการแห่งคุณธรรม หากคุณแสดงอะไรผิดให้ฉันดู ฉันจะหันหลังกลับทันทีแล้วพูดว่า: คุณพูดไร้สาระ ในเวลาเดียวกัน ฉันขอโทษ และทั้งหมดนั้น ฉันจะบันทึกข้อดี ถ้ามี และดำเนินการอื่นๆ ที่ถูกต้อง ในทางกลับกัน ฉันพูดถูกอย่างน่าตกใจเกี่ยวกับเปอร์เซ็นต์ที่มากอย่างน่าตกใจของเวลาทั้งหมด และมันใช้งานไม่ได้ดีนักในความสัมพันธ์กับผู้คน ฉันไม่ได้พยายามที่จะเป็นคนดี แต่ฉันถามคำถามตรงไปตรงมา “สิ่งนี้จะไม่ได้ผล เพราะหนึ่ง สอง และสาม” และพวกเขาก็แบบว่า "โอ้!" ยังมีผลที่ตามมาอื่นๆ ที่อาจดีกว่าที่จะเพิกเฉย เช่น ผลลัพธ์ที่นำไปสู่การหย่าร้างจากภรรยาของฉัน และภาวะซึมเศร้าสิบปีหลังจากนั้น

ความท้าทายคือการต่อสู้กับผู้คน โดยรับรู้ถึงสิ่งที่คุณทำได้หรือทำไม่ได้ สิ่งใดสำคัญและสิ่งใดไม่สำคัญ มีความท้าทายมากมายเกี่ยวกับสไตล์การเขียนโค้ด ฉันยังคงเขียนโค้ดจำนวนมาก และในสมัยนั้นฉันต้องช้าลงเพราะฉันทำงานคู่ขนานมากเกินไปและทำงานได้ไม่ดี แทนที่จะมุ่งเน้นไปที่งานเดียว เมื่อมองย้อนกลับไป ฉันเขียนโค้ดครึ่งหนึ่งสำหรับคำสั่ง Java JIT ซึ่งเป็นคำสั่ง C2 ผู้เขียนโค้ดที่เร็วที่สุดคนถัดไปเขียนช้าครึ่งหนึ่ง อีกครึ่งหนึ่งเขียนช้า และเป็นการลดลงแบบทวีคูณ คนที่เจ็ดในแถวนี้ช้ามาก เกิดขึ้นเสมอ! ฉันสัมผัสโค้ดมากมาย ฉันดูว่าใครเป็นคนเขียน โดยไม่มีข้อยกเว้น ฉันจ้องไปที่โค้ดของพวกเขา ตรวจสอบแต่ละโค้ด และยังคงเขียนตัวเองต่อไปมากกว่าโค้ดใดๆ วิธีการนี้ไม่ค่อยได้ผลกับผู้คน บางคนไม่ชอบสิ่งนี้ และเมื่อพวกเขารับมือไม่ได้ การร้องเรียนทุกประเภทก็เริ่มต้นขึ้น ตัวอย่างเช่น ครั้งหนึ่งฉันเคยถูกบอกให้หยุดเขียนโค้ดเพราะฉันเขียนโค้ดมากเกินไป และมันก็เป็นอันตรายต่อทีม และทุกอย่างฟังดูเหมือนเป็นเรื่องตลกสำหรับฉัน เพื่อน ถ้าสมาชิกในทีมหายไปและฉันเขียนโค้ดต่อไป คุณจะ จะแพ้เพียงครึ่งทีมเท่านั้น ในทางกลับกัน ถ้าฉันเขียนโค้ดต่อไปและคุณเสียทีมไปครึ่งหนึ่ง นั่นฟังดูเป็นการบริหารจัดการที่แย่มาก ฉันไม่เคยคิดถึงมันจริงๆ ไม่เคยพูดถึงมัน แต่มันก็ยังคงอยู่ในหัวของฉัน ความคิดหมุนวนอยู่ในใจของฉัน: “คุณล้อเล่นฉันเหรอ?” ดังนั้นปัญหาที่ใหญ่ที่สุดคือฉันและความสัมพันธ์ของฉันกับผู้คน ตอนนี้ฉันเข้าใจตัวเองดีขึ้นมาก ฉันเคยเป็นหัวหน้าทีมของโปรแกรมเมอร์มาเป็นเวลานาน และตอนนี้ฉันบอกผู้คนโดยตรงว่า คุณก็รู้ ว่าฉันเป็นใคร และคุณจะต้องจัดการกับฉัน - ไม่เป็นไรถ้าฉันยืนหยัด ที่นี่? และเมื่อพวกเขาเริ่มจัดการกับมัน ทุกอย่างก็ดำเนินไป จริงๆ แล้ว ฉันไม่ใช่คนเลวหรือคนดี ฉันไม่มีเจตนาที่ไม่ดีหรือความทะเยอทะยานที่เห็นแก่ตัว มันเป็นเพียงแก่นแท้ของฉัน และฉันต้องอยู่กับมันด้วยวิธีใดวิธีหนึ่ง

แอนดรู: เมื่อไม่นานมานี้ ทุกคนเริ่มพูดถึงการตระหนักรู้ในตนเองสำหรับคนเก็บตัวและทักษะด้านอารมณ์โดยทั่วไป คุณจะพูดอะไรเกี่ยวกับเรื่องนี้?

หน้าผา: ใช่ นั่นคือความเข้าใจและบทเรียนที่ฉันได้เรียนรู้จากการหย่าร้างจากภรรยา สิ่งที่ได้เรียนรู้จากการหย่าร้างคือการเข้าใจตัวเอง เท่านี้ฉันก็เริ่มเข้าใจคนอื่นแล้ว ทำความเข้าใจว่าการโต้ตอบนี้ทำงานอย่างไร สิ่งนี้นำไปสู่การค้นพบทีละคน มีความตระหนักรู้ว่าฉันเป็นใครและเป็นตัวแทนของอะไร ฉันกำลังทำอะไร: ฉันหมกมุ่นอยู่กับงาน หรือฉันกำลังหลีกเลี่ยงความขัดแย้ง หรืออย่างอื่น และการตระหนักรู้ในตนเองในระดับนี้ช่วยให้ตัวเองควบคุมได้จริงๆ หลังจากนี้ทุกอย่างจะง่ายขึ้นมาก สิ่งหนึ่งที่ฉันค้นพบไม่เพียงแต่ในตัวเองเท่านั้น แต่ยังรวมถึงโปรแกรมเมอร์คนอื่นๆ ด้วยคือการไม่สามารถพูดความคิดออกมาได้เมื่อคุณอยู่ในสภาวะที่มีความเครียดทางอารมณ์ ตัวอย่างเช่น คุณกำลังนั่งอยู่ตรงนั้น กำลังเขียนโค้ดอย่างลื่นไหล จากนั้นพวกเขาก็วิ่งเข้ามาหาคุณและเริ่มกรีดร้องด้วยความตกใจว่ามีบางอย่างเสียหาย และตอนนี้เราจะใช้มาตรการที่รุนแรงเพื่อต่อต้านคุณ และคุณไม่สามารถพูดอะไรได้เพราะคุณอยู่ในสภาวะที่มีความเครียดทางอารมณ์ ความรู้ที่ได้รับช่วยให้คุณสามารถเตรียมตัวสำหรับช่วงเวลานี้ เอาชีวิตรอดและก้าวไปสู่แผนการล่าถอย หลังจากนั้นคุณสามารถทำอะไรบางอย่างได้ ใช่แล้ว เมื่อคุณเริ่มรู้ว่ามันทำงานอย่างไร มันเป็นเหตุการณ์ที่เปลี่ยนแปลงชีวิตครั้งใหญ่ 
ตัวฉันเองไม่สามารถหาคำพูดที่เหมาะสมได้ แต่ฉันจำลำดับการกระทำได้ ประเด็นก็คือปฏิกิริยานี้เกิดขึ้นทางกายภาพพอๆ กับทางวาจา และคุณต้องการพื้นที่ พื้นที่ดังกล่าวในความหมายของเซน นี่คือสิ่งที่ต้องอธิบายอย่างชัดเจน จากนั้นให้หลีกทางไปทันที - ถอยออกไปทางร่างกายล้วนๆ เมื่อฉันนิ่งเงียบด้วยวาจา ฉันสามารถประมวลสถานการณ์ทางอารมณ์ได้ เมื่ออะดรีนาลีนเข้าสู่สมองของคุณ เปลี่ยนคุณเข้าสู่โหมดการต่อสู้หรือการบิน คุณจะไม่สามารถพูดอะไรได้อีกต่อไป ไม่ - ตอนนี้คุณเป็นคนงี่เง่า เป็นวิศวกรที่เฆี่ยนตี ไม่สามารถตอบสนองได้ดีหรือแม้แต่หยุดการโจมตี และผู้โจมตีเป็นอิสระ เพื่อโจมตีครั้งแล้วครั้งเล่า ก่อนอื่นคุณต้องเป็นตัวของตัวเองอีกครั้ง ควบคุมได้อีกครั้ง ออกจากโหมด "ต่อสู้หรือหนี"

และสำหรับสิ่งนี้ เราจำเป็นต้องมีพื้นที่ทางวาจา แค่พื้นที่ว่าง หากคุณพูดอะไรเลย คุณสามารถพูดแบบนั้นได้เลย จากนั้นไปหา "พื้นที่" ให้กับตัวเองจริงๆ ไปเดินเล่นในสวนสาธารณะ ขังตัวเองในห้องอาบน้ำ - มันไม่สำคัญ สิ่งสำคัญคือต้องตัดการเชื่อมต่อจากสถานการณ์นั้นชั่วคราว ทันทีที่คุณปิดสวิตช์เป็นเวลาอย่างน้อยสองสามวินาที การควบคุมจะกลับมา คุณจะเริ่มคิดอย่างมีสติ “เอาล่ะ ฉันไม่ใช่คนงี่เง่า ฉันไม่ทำอะไรโง่ๆ ฉันเป็นคนค่อนข้างมีประโยชน์” เมื่อคุณสามารถโน้มน้าวตัวเองได้แล้ว ก็ถึงเวลาก้าวไปสู่ขั้นต่อไป: ทำความเข้าใจกับสิ่งที่เกิดขึ้น คุณถูกโจมตี การโจมตีมาจากที่คุณไม่คาดคิด มันเป็นการซุ่มโจมตีที่ไม่ซื่อสัตย์และเลวทราม นี้ไม่ดี. ขั้นตอนต่อไปคือการทำความเข้าใจว่าเหตุใดผู้โจมตีจึงต้องการสิ่งนี้ จริงเหรอ ทำไม? อาจเป็นเพราะตัวเขาเองโกรธ? ทำไมเขาถึงบ้า? เช่นเพราะเขาทำพังจนไม่สามารถรับผิดชอบได้? นี่เป็นวิธีจัดการกับสถานการณ์ทั้งหมดอย่างระมัดระวัง แต่สิ่งนี้ต้องใช้พื้นที่สำหรับการซ้อมรบและพื้นที่ทางวาจา ขั้นตอนแรกสุดคือการหยุดการติดต่อด้วยวาจา หลีกเลี่ยงการพูดคุยด้วยคำพูด ยกเลิกแล้วเดินออกไปให้เร็วที่สุด ถ้าเป็นการสนทนาทางโทรศัพท์ก็วางสายซะ นี่คือทักษะที่ฉันเรียนรู้จากการสื่อสารกับอดีตภรรยา หากบทสนทนาไม่เป็นไปด้วยดี แค่พูดว่า "ลาก่อน" แล้ววางสาย จากอีกด้านหนึ่งของโทรศัพท์: "blah blah blah" คุณตอบว่า: "ใช่แล้ว ลาก่อน!" และวางสาย คุณเพียงแค่จบการสนทนา ห้านาทีต่อมา เมื่อความสามารถในการคิดอย่างสมเหตุสมผลกลับมาหาคุณ คุณจะเย็นลงเล็กน้อย จึงเป็นไปได้ที่จะคิดถึงทุกสิ่ง เกิดอะไรขึ้น และจะเกิดอะไรขึ้นต่อไป และเริ่มสร้างการตอบสนองอย่างรอบคอบ แทนที่จะตอบสนองโดยใช้อารมณ์เพียงอย่างเดียว สำหรับฉัน ความก้าวหน้าในการตระหนักรู้ในตนเองคือความจริงที่ว่าในกรณีของความเครียดทางอารมณ์ ฉันไม่สามารถพูดได้ การออกจากสภาวะนี้ คิดและวางแผนว่าจะตอบสนองและชดเชยปัญหาอย่างไร นี่เป็นขั้นตอนที่ถูกต้องในกรณีที่คุณไม่สามารถพูดได้ วิธีที่ง่ายที่สุดคือการหนีจากสถานการณ์ที่แสดงความเครียดทางอารมณ์และหยุดมีส่วนร่วมในความเครียดนี้ หลังจากนั้นคุณจะสามารถคิดได้ เมื่อคิดได้ คุณก็จะสามารถพูดได้ และอื่นๆ

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

แอนดรู: มัน... ไม่คาดคิด เยี่ยมมาก เราได้พูดคุยกันมากมายแล้ว และถึงเวลาจบการสัมภาษณ์นี้แล้ว เราจะพบกันในการประชุมอย่างแน่นอนและจะสามารถสานต่อการเจรจานี้ต่อไปได้ เจอกันที่ไฮดรา!

คุณสามารถสนทนาต่อกับ Cliff ได้ที่การประชุม Hydra 2019 ซึ่งจะจัดขึ้นในวันที่ 11-12 กรกฎาคม 2019 ที่เมืองเซนต์ปีเตอร์สเบิร์ก เขาจะมาพร้อมรายงาน "ประสบการณ์หน่วยความจำธุรกรรมฮาร์ดแวร์ Azul". สามารถซื้อตั๋วได้ บนเว็บไซต์อย่างเป็นทางการ.

ที่มา: will.com

เพิ่มความคิดเห็น