แสดงวิธีการต่าง ๆ ในการใช้เธรดใน Delphi

ผู้ใช้ Delphi มากเกินไปทำผิดพลาดในการคิดเธรดเป็นเวทมนตร์ที่จะปรับปรุงประสิทธิภาพของแอปพลิเคชันของพวกเขา น่าเสียดายที่นี่ยังห่างไกลจากความจริง ความผิดพลาดที่ใหญ่ที่สุดอันดับ #1 เมื่อพยายามใช้เธรดกำลังทำให้เข้าถึงการควบคุมภาพของแอปพลิเคชันโดยตรง แต่การควบคุมภาพเหล่านี้สามารถทำงานได้ในบริบทของเธรดหลักของแอปพลิเคชันเท่านั้น การใช้เธรดอื่นเพื่ออัปเดตการควบคุมในส่วนต่อประสานผู้ใช้จะต้องมีการวางแผนและนำไปใช้อย่างรอบคอบ และในกรณีส่วนใหญ่มันอาจไม่ใช่ทางออกที่ถูกต้องสำหรับปัญหาเลย
เพียงแค่ใส่เฟรมเวิร์ก VCL ของ Delphi ไม่ปลอดภัย ในขณะที่มีหลายวิธีในการรวมเธรดเข้ากับ UI ของคุณ แต่ก็ไม่มีโซลูชันเดียวที่เหมาะกับทุกคน มันจะแตกต่างกันไปขึ้นอยู่กับสิ่งที่คุณพยายามทำให้สำเร็จ ส่วนใหญ่ผู้คนต้องการบรรลุประสิทธิภาพที่ดีขึ้น (ความเร็ว) แต่นั่นก็ไม่ค่อยเกิดขึ้นโดยใช้ด้าย แต่สถานการณ์ที่พบบ่อยที่สุดที่เธรดถูกรวมเข้ากับส่วนต่อประสานผู้ใช้คือการตอบสนอง UI นั้นในระหว่างการทำงานที่ยาวนาน
สำหรับสิ่งนี้เราจะจินตนาการถึงแอปพลิเคชั่นง่าย ๆ ที่มีเพียงปุ่มเดียวที่ดาวน์โหลดไฟล์จากอินเทอร์เน็ตเมื่อคลิก แอปพลิเคชันมีเธรดหลักหนึ่งที่ใช้สำหรับ UI ทั้งหมด บนแพลตฟอร์ม Windows ซึ่งหมายถึงการส่ง/รับข้อความ Windows วาดไปยังผืนผ้าใบควบคุมการรับรู้การโต้ตอบของผู้ใช้ ฯลฯ เธรดนี้เป็นห่วงยักษ์ที่หมุนไปรอบ ๆ เร็วจริงๆ สำหรับทุกการปฏิวัติของเธรดการหมุนนี้รหัสบางส่วนจะถูกดำเนินการ
ในสภาพแวดล้อมแบบเธรดเดียวการดาวน์โหลดไฟล์นี้จะบล็อกลูปนี้จากการหมุนจนกว่าการดาวน์โหลดจะเสร็จสิ้น ในช่วงเวลานี้เธรดนี้ไม่สามารถทำการอัปเดต UI ได้อีกต่อไปตรวจจับการคลิกผู้ใช้หรืออะไรก็ตาม นี่คือสิ่งที่ทำให้ Windows ใส่ (ไม่ตอบสนอง) ในชื่อของรูปแบบดังกล่าวเพราะเช่นเดียวกับที่บอกว่ามันไม่ตอบสนอง
นี่คือที่มาของเธรดเพิ่มเติมเข้ามามันจำเป็นต้องตอบสนองต่อ Windows แทนที่จะปิดกั้นเธรด UI หลักด้วยการดาวน์โหลดไฟล์ยักษ์นี้คุณสามารถวางไฟล์นั้นลงในเธรดอื่นได้ มันเรียบง่ายใช่มั้ย
คุณอาจถามตัวเองว่า "ฉันจะตรวจสอบความคืบหน้าได้อย่างไร" หรือ "ฉันจะได้รับการแจ้งเตือนอย่างไรเมื่อเสร็จแล้ว" นี่หมายถึงเธรดการดาวน์โหลดจำเป็นต้องโต้ตอบกับเธรดหลัก นี่คือที่ที่ความสับสนเข้ามาหนึ่งเธรดหนึ่งไม่สามารถรบกวนเธรดอื่นได้เพราะไม่มีการบอกว่ามีเธรดหนึ่งจุดที่จริง ตอนนี้มีลูปแยกกันสองตัวและเมื่อคุณต้องการอัปเดต UI นั้นเธรด UI นั้นสามารถทำอะไรก็ได้ สิ่งสำคัญที่สุดคือสมมติว่าเธรด UI หลักอยู่ในขั้นตอนการเขียนสตริงไปยังคุณสมบัติการควบคุมเดียวกันซึ่งเธรดอื่น ๆ ของคุณยังต้องการเขียน ตอนนี้คุณมีสองเธรดที่พยายามเขียนไปยังที่อยู่หน่วยความจำเดียวกันซึ่งอาจส่งผลให้เกิดปัญหาที่คาดเดาไม่ได้
โดยการซิงโครไนซ์ คลาส tthread ของ Delphi มีวิธีการซิงโครไนซ์ () ซึ่งอนุญาตให้เธรดโต้ตอบกับเธรด UI หลักได้ในช่วงเวลาที่มันจะทำงานได้อย่างถูกต้องจริง ๆ เมื่อคาดว่าจะเกิดขึ้นจริง รหัสที่ซิงโครไนซ์จากเธรดอื่นไม่ได้ทำงานในบริบทของเธรดนั้น - มันจะทำงานในบริบทของเธรด UI หลักเสมอ นั่นคือแนวคิดของการซิงโครไนซ์ () คือการเรียกใช้รหัสในเธรด UI
ดังนั้นในที่สุดคุณไม่ได้ใช้ VCL จากเธรด แต่เธรดของคุณจะส่งสัญญาณไปยังเธรดหลักและเฉพาะเมื่อเธรดหลักพร้อมจะเรียกใช้รหัสนั้น ในขณะเดียวกันเธรดรองของคุณก็ถูกบล็อกในขณะที่รอให้เธรดหลักเสร็จสิ้น
จากนั้นก็มีความผิดพลาดในการคิดว่าการดำเนินการ UI ขนาดใหญ่จะดีกว่าในเธรด สมมติว่าคุณมีรายการที่คุณต้องการเติมรายการหลายล้านรายการ แน่นอนว่าต้องใช้เวลาและในช่วงเวลานี้ใบสมัครของคุณจะไม่ตอบสนอง อีกครั้ง. ดังนั้นเพียงแค่ย้ายรหัสนั้นไปที่เธรดใช่ไหม
อีกครั้งการโต้ตอบ UI ใด ๆ จะต้องทำจากเธรดหลักและเธรดหลักเท่านั้น เธรดมีประโยชน์หากคุณต้องการทำการคำนวณที่ยาวนานประมวลผลข้อมูลจำนวนมหาศาลรอการตอบกลับจากทรัพยากรระยะไกลหรือสิ่งอื่นใดที่ใช้เวลานานและไม่เกี่ยวข้องโดยตรงกับ UI
มันยากที่จะพูด แต่มีวิธีปฏิบัติทั่วไปที่แนะนำอย่างมากเมื่อเขียนเธรด: ใส่รหัสเธรดของคุณในหน่วยของตัวเอง หน่วยนี้ควรแยกได้จากหน่วย UI อื่น ๆ ไม่ควรมียูนิตที่เกี่ยวข้องกับ VCL ในประโยคการใช้งาน เธรดไม่ควรรู้ด้วยซ้ำว่ามีการใช้งานอย่างไร มันควรจะเป็นหุ่นจำลองโดยมีวัตถุประสงค์เพียงอย่างเดียวในการปฏิบัติงานที่ยาวนานของคุณ เมื่อพูดถึงการอัปเดต UI จากเธรดสิ่งนี้ทำได้ดีที่สุดโดยเหตุการณ์ที่ซิงโครไนซ์
สิ่งที่ดูเหมือน มันเป็นเหตุการณ์ที่ซิงโครไนซ์ดังที่อธิบายไว้ก่อนหน้านี้ เหตุการณ์เป็นเพียงตัวชี้ไปยังขั้นตอนที่คุณสามารถกำหนดให้กับเธรดก่อนที่จะเริ่ม ภายในเธรดเมื่อคุณต้องการอัปเดต UI คุณจะใช้ซิงโครไนซ์ () เพื่อเรียกเหตุการณ์นี้ ด้วยการออกแบบนี้เธรดจะไม่เคยรู้เลยว่ามันถูกใช้โดย UI ในขณะเดียวกันคุณก็ทำสิ่งที่เป็นนามธรรมโดยไม่ได้ตั้งใจ เธรดกลายเป็นอีกครั้ง คุณสามารถเสียบเข้ากับโครงการอื่น ๆ ซึ่งอาจไม่มีส่วนติดต่อผู้ใช้ (สมมติว่าบริการ Windows)
นี่คือลิงค์โดยตรงไปยังแหล่งข้อมูลที่เกี่ยวข้องเกี่ยวกับความปลอดภัยของเธรด VCL ในกรณีที่คุณไม่ต้องการค้นหา ...
แอปพลิเคชันนี้แสดงให้เห็นถึงการใช้เธรดใน Delphi เนื่องจากมีหลายสิ่งที่ต้องรู้พวกเขาจึงถูกแบ่งออกเป็นส่วนต่าง ๆ เพื่อจุดประสงค์ที่แตกต่างกัน แต่ละหัวข้อมีหน่วยอย่างน้อย 1 ชุด (ฝังลงในแผ่นแท็บ) และอย่างน้อย 1 หน่วยแบบสแตนด์อโลนที่มีฟังก์ชั่นของมันนอกเหนือจากส่วนต่อประสานผู้ใช้ สิ่งนี้ทำโดยมีวัตถุประสงค์เพื่อแสดงให้เห็นว่าเธรด ควร ถูกแยกออกจาก UI ใด ๆ
แบบฟอร์มหลักนั้นไม่มีตรรกะใด ๆ ทั้งหมดที่มันคือฝังแบบฟอร์มลงในแท็บ ในตัวจัดการเหตุการณ์ FormCreate() มันทำให้การโทรไปยัง EmbedForm() จำนวนมากซึ่งสร้างแบบฟอร์มสำหรับแต่ละแท็บแผ่น
การใช้แอปพลิเคชันนั้นง่ายมาก คุณเพียงแค่นำทางไปยังหนึ่งในแท็บและแต่ละแท็บจะมีคำแนะนำของตัวเอง


แสดงวิธีการดาวน์โหลดไฟล์จากอินเทอร์เน็ตในเธรด มีฟังก์ชั่นสากลเดี่ยวที่กำหนด DownloadFile() ซึ่งทำการดาวน์โหลด UI มี 3 ปุ่ม:
โดยค่าเริ่มต้น URL ที่จะดาวน์โหลดคือไฟล์ทดสอบที่จัดทำโดย ThinkBroadband.com แต่คุณสามารถใช้ URL ใด ๆ ที่คุณต้องการ คุณยังสามารถเลือกตำแหน่งเพื่อบันทึกไฟล์ไป นี่เป็นตัวอย่างที่ง่ายมากดังนั้นชื่อไฟล์/ส่วนขยายของชื่อไฟล์ท้องถิ่นจะต้องปรับให้เข้ากับความต้องการของคุณ - มันจะไม่เปลี่ยนแปลงโดยอัตโนมัติสำหรับ URL ที่คุณกำลังดาวน์โหลด (ตามที่เบราว์เซอร์ทำ)

แสดงวิธีอัปเดตแถบความคืบหน้าจากเธรดที่ทำงานยาว

สาธิตการใช้การเชื่อมต่อฐานข้อมูลภายในเธรดและซิงโครไนซ์ข้อมูลกับเธรด UI

แสดงให้เห็นถึงหลายเธรดที่ใช้วงจร CPU ขนาดใหญ่เพื่อโหลดทดสอบโปรเซสเซอร์ของคุณ