สร้างไปป์ไลน์ด้วย PowerShell 7 และ ForEach-Object -Parallel

การปรับปรุงครั้งล่าสุด: 17/12/2025
ผู้แต่ง: ไอแซก
  • PowerShell มันมีวิธีการวนซ้ำหลายวิธี (foreach, ForEach-Object, ForEach method, for, while, do-while, do-until) ซึ่งแต่ละวิธีก็ส่งผลต่อประสิทธิภาพและหน่วยความจำแตกต่างกันไป
  • คำสั่ง ForEach-Object -Parallel ใน PowerShell 7 อนุญาตให้ประมวลผลองค์ประกอบของไปป์ไลน์แบบขนาน โดยควบคุมการทำงานพร้อมกันผ่าน ThrottleLimit และยอมเสียลำดับการแสดงผลไปบ้าง
  • คำสั่ง Start-Job, Start-ThreadJob, runspaces และ Workflows แบบดั้งเดิมที่ใช้ foreach -Parallel นำเสนอรูปแบบการทำงานแบบขนานอื่นๆ ที่มีโอเวอร์โหลดและระดับการแยกการทำงานที่แตกต่างกัน
  • การวัดประสิทธิภาพ การหลีกเลี่ยงข้อผิดพลาดทั่วไปของคำสั่ง forach และการประยุกต์ใช้การควบคุมการไหลและการจัดการข้อผิดพลาดที่ดี เป็นกุญแจสำคัญในการสร้างไปป์ไลน์ที่มีประสิทธิภาพและเสถียร

วิธีดูประวัติคำสั่งใน PowerShell และ CMD

เมื่อคุณเริ่มใช้งาน PowerShell ไม่ช้าก็เร็วคุณจะต้องเจอปัญหาเดียวกัน: คุณมี วัตถุจำนวนมากที่ต้องประมวลผลในลูป และประสิทธิภาพก็ลดลงอย่างมาก ตัวอย่างเช่น กล่องจดหมาย Exchange ไฟล์บนเซิร์ฟเวอร์ กระบวนการทำงานบนเครื่องหลายเครื่อง เป็นต้น จัดการพีซีและเซิร์ฟเวอร์หลายเครื่อง…ทุกอย่างไหลผ่านท่อส่งและแบบคลาสสิก ForEach-Objectแต่แน่นอนว่า วงจรนั้นทำงานไปทีละองค์ประกอบตามลำดับ และจะมีจุดหนึ่งที่มันทำงานไม่สำเร็จ

การมาถึงของ PowerShell 7 ทำให้สถานการณ์เปลี่ยนแปลงไปอย่างมาก ตอนนี้เรามีเครื่องมือมากมายให้เลือกใช้ การประมวลผลแบบไปป์ไลน์คู่ขนานด้วย ForEach-Object -Parallel และวิธีการทำงานแบบขนานอื่นๆ ที่ช่วยให้สามารถใช้ประโยชน์จากคอร์ CPU ได้ดียิ่งขึ้น เวลา กำลังรอการทำงานของเครือข่ายหรือดิสก์ เคล็ดลับคือการทำความเข้าใจว่าแต่ละตัวเลือกทำอะไร เมื่อไหร่ควรใช้ และวิธีการจำกัดการทำงานพร้อมกันเพื่อไม่ให้ประสิทธิภาพลดลง แต่กลับดีขึ้น

ลูปใน PowerShell: จุดเริ่มต้น

ก่อนที่จะเจาะลึกเรื่องไปป์ไลน์แบบขนาน เราควรทำความเข้าใจก่อนว่าลูปคืออะไร และโครงสร้างต่างๆ ของ PowerShell ทำงานอย่างไร โดยพื้นฐานแล้ว ลูปเป็นวิธีการหนึ่งในการ... ทำซ้ำคำแนะนำอย่างน้อยหนึ่งข้อหลายครั้งการทำงานแบบนี้สามารถเกิดขึ้นได้กับจำนวนรอบที่กำหนดไว้ หรือจนกว่าเงื่อนไขบางอย่างจะเป็นไปตามที่กำหนด ในการบริหารระบบนั้นเป็นเรื่องปกติ เช่น การกำหนดสิทธิ์ให้กับผู้ใช้ทั้งหมดในกลุ่ม การสำรวจไฟล์หลายพันไฟล์ในไดเร็กทอรี หรือการประมวลผลเหตุการณ์ต่างๆ รับ WinEvent.

PowerShell มีโครงสร้างควบคุมแบบคลาสสิกหลายแบบ เช่น for, foreach, while, do-while y do-untilนอกจาก cmdlet และเมธอดที่อนุญาตให้วนซ้ำแล้ว ยังมีตัวอย่างเช่น ForEach-Object หรือวิธีการ .ForEach() ในชุดข้อมูลต่างๆ ทั้งหมดนี้เป็นพื้นฐานที่เราสามารถใช้สร้างตรรกะที่ซับซ้อนยิ่งขึ้นได้ รวมถึงการประมวลผลแบบขนานด้วย

foreach เทียบกับ ForEach-Object เทียบกับเมธอด ForEach

ใน PowerShell มีความสับสนอยู่บ้างเพราะเรามี สามวิธีที่แตกต่างกันในการใช้คำสั่ง “foreach” และพวกมันก็ไม่ได้ทำงานเหมือนกัน ในแง่ไวยากรณ์พวกมันคล้ายกัน แต่ภายในแล้วสิ่งต่างๆ เปลี่ยนไปค่อนข้างมาก โดยเฉพาะอย่างยิ่งในเรื่องการใช้หน่วยความจำและไปป์ไลน์

คำหลัก foreach (คำสั่ง foreach)

คำสำคัญ foreach นี่คือโครงสร้างลูปแบบ "คลาสสิก" ของภาษา โหลด ข้อมูลทั้งหมดจะถูกจัดเก็บไว้ในหน่วยความจำ และแต่ละองค์ประกอบจะถูกประมวลผลตามลำดับวิธีนี้สะดวกและรวดเร็วมากเมื่อคุณมีอาร์เรย์หรือคอลเลกชันอื่น ๆ อยู่ในหน่วยความจำอยู่แล้ว และขนาดของมันเหมาะสม กระบวนการทำงานมีดังนี้: ขั้นแรก PowerShell จะตรวจสอบจำนวนองค์ประกอบ จากนั้นจะกำหนดองค์ประกอบแต่ละตัวให้กับตัวแปรทีละตัว (ตัวอย่างเช่น $item) และดำเนินการบล็อกโค้ดในแต่ละรอบ

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

คำสั่ง ForEach-Object ในไปป์ไลน์

คำสั่ง Cmdlet ForEach-Object มันทำงานแตกต่างออกไป: มันถูกออกแบบมาเพื่อ ประมวลผลวัตถุทีละชิ้นเมื่อวัตถุนั้นเข้ามาทางไปป์ไลน์กล่าวอีกนัยหนึ่งคือ ไม่จำเป็นต้องโหลดคอลเลกชันทั้งหมดตั้งแต่เริ่มต้น ทำให้มีประสิทธิภาพมากสำหรับสถานการณ์ที่แหล่งข้อมูลสามารถสร้างรายการได้จำนวนมาก (ตัวอย่างเช่น Get-ChildItem (ในโครงสร้างโฟลเดอร์ขนาดใหญ่) หรือเมื่อคุณไม่ต้องการหรือไม่สามารถจัดเก็บคอลเลกชันทั้งหมดไว้ในหน่วยความจำ หรือเมื่อใช้เครื่องมือภายนอก เช่น Git จาก PowerShell.

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

เมธอด ForEach() ในคอลเลกชัน

ตั้งแต่ PowerShell 5 เป็นต้นมา คอลเลกชันหลายประเภท เช่น อาร์เรย์และลิสต์ ได้เปิดเผยเมธอดดังกล่าว .ForEach()ซึ่งช่วยให้ ใช้สคริปต์บล็อกกับแต่ละองค์ประกอบด้วยวิธีที่กระชับมาก. ยกตัวอย่างเช่น $array.ForEach({ ... })วิธีการนี้เป็นแบบเชิงวัตถุและมีประโยชน์มากเมื่อคุณต้องการเชื่อมโยงการดำเนินการต่างๆ และทำงานกับคอลเลกชันที่มีอยู่แล้วได้อย่างราบรื่น

ในแง่ของประสิทธิภาพ วิธีการนี้ .ForEach() โดยปกติ มีประสิทธิภาพมากกว่าคำสั่ง ForEach-Object เมื่อทุกอย่างอยู่ในหน่วยความจำแล้ว คุณจะหลีกเลี่ยงกลไกบางส่วนของกระบวนการทำงานได้ อย่างไรก็ตาม มันก็ยังมีข้อจำกัดพื้นฐานเดียวกัน คือ มันทำงานกับชุดข้อมูลที่ถูกสร้างขึ้นแล้ว ดังนั้นจึงไม่ใช่เครื่องมือที่เหมาะสมสำหรับการสตรีมข้อมูลปริมาณมาก

ความแตกต่างในทางปฏิบัติระหว่าง foreach และ ForEach-Object

ในการปฏิบัติงานประจำวัน คำถามต่างๆ มักเกิดขึ้น เช่น “ทำไมถึงเป็นเช่นนี้” ต้นฉบับ สหรัฐอเมริกา Get-Mailbox ... | ForEach-Object { ... } และอีกคนหนึ่งก็ทำก่อน $Mailboxes = Get-Mailbox ... แล้ว a foreach ($Mailbox in $Mailboxes)ความแตกต่างหลักคือ ในกรณีแรก ทุกอย่างจะผ่านกระบวนการทำงานแบบเป็นขั้นตอน โดยประมวลผลกล่องจดหมายแต่ละกล่องเมื่อมาถึงในขณะที่ในวิธีที่สอง ข้อมูลทั้งหมดจะถูกเก็บไว้ในตัวแปร $Mailboxes แล้วคุณก็เดินทางท่องเที่ยวไปรอบๆ

  WinZip เทียบกับ WinRAR สำหรับ Windows: การทดสอบ รูปแบบ ความเร็ว และความปลอดภัย

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

ลูปประเภทอื่นๆ: for, while, do-while, do-until

นอกจากระบบนิเวศของ foreach แล้ว PowerShell ยังมีลูปแบบดั้งเดิมอื่นๆ ที่ยังคงมีประโยชน์มาก ลูป foreach for อนุญาตให้วนซ้ำในช่วงของตัวเลขการเพิ่มหรือลดค่าดัชนีไปเรื่อยๆ จนกว่าเงื่อนไขจะไม่เป็นจริงอีกต่อไป เป็นความคิดที่ดี เหมาะอย่างยิ่งสำหรับการวนลูปผ่านอาร์เรย์ตามตำแหน่ง การข้ามองค์ประกอบ หรือการเข้าถึงองค์ประกอบในลำดับย้อนกลับ

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

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

การควบคุมการไหลอย่างละเอียด: หยุด ไหลต่อ และไหลกลับ

เพื่อให้สามารถควบคุมสิ่งที่เกิดขึ้นภายในลูปได้ดียิ่งขึ้น เราจึงมีคำสำคัญหลักสามคำดังนี้: break, continue y returnแม้ว่าบางครั้งจะถูกมองข้ามไป แต่สิ่งเหล่านี้สร้างความแตกต่างอย่างมากในบทภาพยนตร์ที่ซับซ้อน

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

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

ในที่สุด return ไม่เพียงแต่ทำลายวงจรเท่านั้นนอกจากจะส่งค่ากลับจากฟังก์ชันหรือสคริปต์แล้ว มันยังส่งค่ากลับอีกอย่างหนึ่งด้วย เหมือนกับการพูดว่า "ฉันได้สิ่งที่ต้องการแล้ว นี่ไง และฉันจะไปแล้ว" หากใช้ให้ถูกวิธี มันจะช่วยลดความซับซ้อนของตรรกะในสคริปต์ได้อย่างมาก

ForEach-Object -Parallel ใน PowerShell 7

PowerShell 7 ได้นำเสนอคุณสมบัติใหม่ที่ทรงพลังมาก: พารามิเตอร์ -Parallel ของ cmdlet ForEach-Objectฟังก์ชันนี้ ซึ่งเพิ่มเข้ามาครั้งแรกในเวอร์ชันเบต้า 3 ของเวอร์ชัน 7.0 ช่วยให้สามารถประมวลผลองค์ประกอบไปป์ไลน์หลายรายการพร้อมกันได้ โดยไม่ต้องใช้โมดูลภายนอกหรือโค้ดที่ซับซ้อนพร้อมรันสเปซ

แนวคิดนี้เรียบง่าย: แทนที่จะประมวลผลวัตถุทีละชิ้นตามลำดับคำสั่ง cmdlet นี้สามารถเรียกใช้งานหลายรอบพร้อมกันได้ โดยแต่ละรอบจะเรียกใช้บล็อกสคริปต์กับองค์ประกอบที่แตกต่างกันในคอลเลกชัน ด้วยวิธีนี้ หากคุณมีงานอิสระหลายงาน (เช่น การร้องขอ HTTP หลายรายการ การคัดลอกไฟล์หลายไฟล์ไปยังปลายทางที่แตกต่างกัน หรือการสืบค้นข้อมูลจากกล่องจดหมายจำนวนมาก) คุณสามารถลดเวลาการทำงานโดยรวมได้อย่างมาก

พฤติกรรมของ ForEach-Object ก่อนและหลัง -Parallel

โดยไม่มีพารามิเตอร์ -Parallel, ForEach-Object ประมวลผลองค์ประกอบตามลำดับทีละชิ้น รอให้แต่ละบล็อกเสร็จสมบูรณ์ก่อนจึงค่อยไปยังบล็อกถัดไป หากคุณลองทดสอบง่ายๆ ด้วยวัตถุ 10 ชิ้นและหยุดชั่วคราวสั้นๆ คุณจะเห็นว่าเวลาทั้งหมดแทบจะเท่ากับผลรวมของเวลาแต่ละส่วนทั้ง 10 ครั้ง

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

ลำดับการออกและจำนวนการดำเนินการพร้อมกัน

มีรายละเอียดสำคัญอย่างหนึ่งคือ เมื่อคุณใช้งาน ForEach-Object -Parallel, ลำดับของผลลัพธ์ไม่ได้รับการรับประกันอีกต่อไปรายการต่างๆ จะถูกส่งคืนเมื่อภารกิจเสร็จสมบูรณ์ ไม่ใช่ตามลำดับเดิม หากตรรกะของคุณขึ้นอยู่กับลำดับ คุณจะต้องจัดเรียงลำดับใหม่ในภายหลัง หรือใส่ข้อมูลดัชนีเพื่อสร้างลำดับใหม่ขึ้นมา

โดยค่าเริ่มต้น PowerShell 7 จะทำงาน การดำเนินการพร้อมกันห้าอย่างหากคุณต้องการปรับค่านี้ ให้ใช้พารามิเตอร์ ThrottleLimitนี่เป็นการกำหนดจำนวนองค์ประกอบสูงสุดที่สามารถประมวลผลพร้อมกันได้ การกำหนดค่าอย่างถูกต้องเป็นกุญแจสำคัญในการหาจุดสมดุลที่เหมาะสมระหว่างความเร็วและการใช้ทรัพยากร

เมื่อใดที่ไม่ควรใช้การประมวลผลแบบขนาน?

ไม่ใช่ทุกปัญหาจะแก้ได้ด้วยการเปรียบเทียบแบบไม่เลือกปฏิบัติ ในบางสถานการณ์ เช่น การถ่ายโอนไฟล์ขนาดใหญ่ผ่านเครือข่ายที่มีข้อจำกัดการดำเนินการหลายอย่างพร้อมกันมากเกินไปอาจทำให้แบนด์วิดท์เต็มและส่งผลให้ทุกอย่างช้าลงอย่างไม่น่าเชื่อ เช่นเดียวกับ API หรือบริการระยะไกลที่มีข้อจำกัดด้านจำนวนคำขอ

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

  คุณควรรู้ว่าคุณสามารถทำอะไรได้บ้างใน Windows 10 หากเครื่องพิมพ์ HP ของคุณไม่สแกน

ตัวเลือกอื่นๆ สำหรับการเรียกใช้แบบขนานใน PowerShell

นอกจากนี้แล้ว ForEach-Object -ParallelPowerShell เสนอ วิธีการทำงานแบบขนานหลายวิธีทั้งในเวอร์ชันเก่าและเวอร์ชัน 7.x แต่ละเวอร์ชันมีข้อดีและข้อเสีย และสิ่งสำคัญคือต้องทราบข้อมูลเหล่านั้นเพื่อเลือกใช้เครื่องมือที่เหมาะสม

Start-Job: งานในกระบวนการอิสระ

คำสั่ง Cmdlet Start-Job ฟังก์ชันนี้มีอยู่ใน PowerShell ทุกเวอร์ชันและจะเริ่มทำงาน ทำงานในกระบวนการที่แยกจากกัน โดยแต่ละกระบวนการมีอินสแตนซ์ของ PowerShell เป็นของตัวเองวิธีนี้ให้การแยกส่วนที่แข็งแกร่ง แต่ก็มีค่าใช้จ่ายเพิ่มเติมมาก เช่น การสร้างกระบวนการใหม่ การแปลงอ็อบเจ็กต์เป็นรูปแบบอนุกรมและการแปลงกลับ เป็นต้น

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

Start-ThreadJob: งานที่ใช้เธรด

โมดูล เธรดจ็อบ จัดเตรียม cmdlet Start-ThreadJobซึ่งใช้รันสเปซในการสร้าง งานที่เบากว่างานที่ Start-Jobการแบ่งปันกระบวนการช่วยหลีกเลี่ยงการสูญเสียข้อมูลประเภทต่างๆ ที่เกิดจากการแปลงข้อมูลเป็นลำดับระหว่างกระบวนการได้เป็นอย่างมาก

ใน PowerShell 7 และเวอร์ชันที่ใหม่กว่า โมดูล ThreadJob ได้ถูกรวมไว้แล้ว ในขณะที่ใน Windows สามารถติดตั้ง PowerShell 5.1 ได้จาก PowerShell Gallery Start-ThreadJob รองรับพารามิเตอร์ ThrottleLimitวิธีนี้ช่วยให้คุณควบคุมจำนวนงานเหล่านี้ที่ทำงานพร้อมกันได้ ซึ่งจะช่วยป้องกันไม่ให้ทรัพยากรระบบหมดลง

พื้นที่รันสเปซและ SDK ของ PowerShell

สำหรับสถานการณ์ขั้นสูง คุณสามารถทำงานโดยตรงกับเนมสเปซได้ System.Management.Automation.Runspaces จาก PowerShell SDK สิ่งนี้ช่วยให้คุณสร้างตรรกะการทำงานแบบขนานที่ละเอียดมาก ควบคุมการจัดการพื้นที่ทำงาน พูล การซิงโครไนซ์ ฯลฯ อันที่จริง ทั้งสองอย่าง ForEach-Object -Parallel ในขณะที่ Start-ThreadJob พวกเขาอาศัย runspace ภายในเป็นหลัก

แนวทางนี้เสนอ ความยืดหยุ่นสูงสุดและศักยภาพในการทำงานสูงสุดอย่างไรก็ตาม วิธีนี้ก็หมายถึงความซับซ้อนและโค้ด "การเชื่อมต่อ" ที่มากขึ้นด้วย ในหลายกรณี คำสั่ง cmdlet ในตัว (ForEach-Object -Parallel และ Start-ThreadJob) ก็ครอบคลุมความต้องการส่วนใหญ่ได้แล้ว จึงไม่จำเป็นต้องใช้โค้ดที่ซับซ้อนเช่นนั้น

เวิร์กโฟลว์และคำสั่ง foreach -Parallel ใน Windows PowerShell

Windows PowerShell 5.1 มีฟังก์ชันการทำงานดังต่อไปนี้ เวิร์กโฟลว์สคริปต์ชนิดพิเศษที่ออกแบบมาสำหรับงานที่ใช้เวลานาน โดยมีความสามารถในการหยุดชั่วคราว ดำเนินการต่อ และทำงานแบบขนานได้ โครงสร้างนี้สามารถนำไปใช้ภายในเวิร์กโฟลว์ได้ foreach -Parallelที่ เรียกใช้บล็อกสคริปต์หนึ่งครั้งสำหรับแต่ละองค์ประกอบในคอลเลกชันพร้อมกัน.

ไวยากรณ์พื้นฐานของ foreach -Parallel มันเป็นอย่างนั้น foreach -Parallel ($item in $collection) { ... }และ ใช้ได้เฉพาะภายในเวิร์กโฟลว์เท่านั้นองค์ประกอบต่างๆ ของชุดสะสมจะถูกประมวลผลไปพร้อมๆ กัน ในขณะที่ คำสั่ง ภายในบล็อกนั้น คำสั่งต่างๆ จะถูกดำเนินการตามลำดับสำหรับแต่ละองค์ประกอบ (แม้ว่าจะสามารถผสมผสานกับบล็อกอื่นๆ ได้เช่นกัน) parallel { ... } ภายใน).

อย่างไรก็ตาม ขั้นตอนการทำงาน ฟังก์ชันเหล่านี้ไม่สามารถใช้งานได้ใน PowerShell เวอร์ชัน 7 หรือเวอร์ชันที่ใหม่กว่านอกจากนี้ยังไม่แนะนำให้ใช้ในการพัฒนาโปรแกรมใหม่ อย่างไรก็ตาม การทำความเข้าใจไวยากรณ์และแนวคิดก็คุ้มค่า หากคุณยังคงดูแลสคริปต์เก่าที่ใช้ไวยากรณ์เหล่านี้อยู่ foreach -Parallelเนื่องจากพฤติกรรมของมันแตกต่างจากทั้ง foreach ปกติและ ForEach-Object -Parallel

จำกัดการใช้งานพร้อมกันด้วย ThrottleLimit

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

เพื่อสร้างความสมดุลในด้านนี้ Start-ThreadJob y ForEach-Object -Parallel พวกเขาเสนอพารามิเตอร์ ThrottleLimitการตั้งค่านี้จะกำหนดจำนวนงานหรือรอบการทำงานสูงสุดที่สามารถดำเนินการพร้อมกันได้ หากคุณพยายามเริ่มงานมากกว่าจำนวนที่อนุญาต งานเหล่านั้นจะถูกจัดคิวไว้จนกว่าจะมีงานใดงานหนึ่งเสร็จสิ้นและทำให้พื้นที่ว่างลง

ตั้งแต่ PowerShell เวอร์ชัน 7.1 เป็นต้นมา ForEach-Object -Parallel นำ runspace จากพูลเริ่มต้นมาใช้ซ้ำและค่าของ ThrottleLimit ระบุขนาดของพูลนั้น ค่าเริ่มต้นคือ 5 ซึ่งโดยทั่วไปถือเป็นจุดเริ่มต้นที่ดี นอกจากนี้ยังมีตัวแก้ไขเพื่อสร้างรันสเปซใหม่สำหรับแต่ละรอบการทำงาน (UseNewRunspaceแต่จะคุ้มค่าก็ต่อเมื่อคุณต้องการฉนวนกันความร้อนที่แข็งแกร่งมากและยอมรับการรับน้ำหนักเกินได้มากขึ้น

ในทางกลับกัน ซม Start-Job ขาด ThrottleLimitดังนั้น หากคุณไม่ควบคุมด้วยตนเอง คุณอาจมีกระบวนการ PowerShell หลายสิบหรือหลายร้อยกระบวนการทำงานพร้อมกัน ซึ่งจะส่งผลกระทบต่อประสิทธิภาพและหน่วยความจำในที่สุด

การวัดประสิทธิภาพของวิธีการต่างๆ

วิธีที่เหมาะสมในการตัดสินใจว่าจะใช้โมเดลการประมวลผลแบบขนานแบบใดคือ วัดเวลาการทำงานจริงสำหรับกรณีการใช้งานของคุณในการทำเช่นนี้ คุณสามารถใช้ฟังก์ชันเช่น Measure-Parallelซึ่งเป็นการเปรียบเทียบความเร็วของวิธีการต่างๆ: Start-Job, Start-ThreadJob, ForEach-Object -Parallel y Start-Process.

ฟังก์ชันนี้สร้างชุดข้อมูลจำลอง (เช่น ชื่อไฟล์ ZIP) สร้าง "ชุดข้อมูล" หรือเซสชันการทำงานหลายชุด และสำหรับแต่ละวิธีการ จะวัดระยะเวลาที่ใช้ในการประมวลผลองค์ประกอบจำนวนหนึ่ง โดยใช้ ขนาดชุดข้อมูลถูกกำหนดโดย BatchSize และผลงานทั้งหมด JobCountนอกจากนี้ยังปรับวิธีการที่มีอยู่ให้เหมาะสมกับเวอร์ชันของ PowerShell และการมีอยู่หรือไม่มีอยู่ของ Start-ThreadJob.

ข้างใน, Measure-Parallel กำหนดค่าไฟล์ปฏิบัติการ (เช่น cmd.exe o shโดยมีรายการอาร์กิวเมนต์ และกำหนดแฮชเทเบิลที่มีการใช้งานเฉพาะสำหรับแต่ละแนวทาง Measure-Command คำนวณเวลาทั้งหมด ด้วยการประมวลผลชุดข้อมูลทั้งหมดสำหรับแต่ละทางเลือก ระบบจึงสามารถดูข้อความโดยละเอียดได้ -Verbose สุดท้ายนี้ ฟังก์ชันจะส่งคืนอ็อบเจ็กต์ที่มีข้อมูลสรุปของเวลา เพื่อให้สามารถเปรียบเทียบได้อย่างง่ายดาย

  วิธีเปิดใช้งานตารางใน Paint และควบคุมตัวเลือกทั้งหมด

การรันอะไรบางอย่างเช่น Measure-Parallel -Approach All -BatchSize 5 -JobCount 20 -Verbose บนคอมพิวเตอร์ Windows ที่ใช้ PowerShell 7.5.1 พบว่า ในกรณีเฉพาะนั้น Start-Process เพื่อให้ได้เวลาที่สั้นที่สุดตามด้วย ForEach-Object -Parallel y Start-ThreadJobในขณะที่ Start-Job ปรากฏว่าวิธีนี้เป็นวิธีที่ช้าที่สุด เนื่องจากมีค่าใช้จ่ายสูงมากในการเรียกใช้กระบวนการย่อยของ PowerShell

ความขนานและลูป foreach แบบ "ดั้งเดิม"

สิ่งหนึ่งที่มักเกิดขึ้นในทางปฏิบัติคือ เมื่อคุณย้ายเวิร์กโฟลว์และสคริปต์เก่าๆ ไปยัง PowerShell 7 คุณจะเริ่มพบกับปัญหาต่างๆ แทนที่การตั้งค่า runspace ด้วยตนเองด้วยโมดูลจากภายนอก เช่น PoshRSJob หรือ Workflows โดยใช้เครื่องมือที่ผสานรวมไว้แล้ว เช่น Start-ThreadJob y ForEach-Object -Parallelวิธีนี้ช่วยลดความซับซ้อนของโค้ดและลดจำนวนการพึ่งพาภายนอก นอกจากนี้ยังนิยมบูรณาการโซลูชันอัตโนมัติ เช่น พาวเวอร์เชลล์ DSC.

ผู้ดูแลระบบบางรายที่ใช้พูลรันสเปซแบบแมนนวลเริ่มประสบปัญหาพฤติกรรมที่ไม่เสถียร (เช่น สคริปต์หยุดทำงานโดยไม่ทราบสาเหตุในสภาพแวดล้อมการใช้งานจริง) และเมื่อเผชิญกับความยากลำบากในการแก้ไขปัญหาเหล่านี้ จึงเลือกใช้ ลดความซับซ้อนและอาศัยฟังก์ชันการทำงานแบบขนานที่บูรณาการเข้าด้วยกัน ซึ่งได้รับการทดสอบและรับรองโดยทีมงาน PowerShell แล้ว

เทคนิคขั้นสูงในการใช้ foreach: การซ้อนคำสั่ง, การกรองข้อมูล และการจัดการข้อผิดพลาด

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

ภายใน foreach การใช้เป็นเรื่องปกติ เงื่อนไข if เพื่อประมวลผลองค์ประกอบต่างๆ ในรูปแบบที่แตกต่างกัน โดยพิจารณาจากคุณสมบัติของไฟล์ ตัวอย่างเช่น การวนลูปผ่านไฟล์ทั้งหมดในไดเร็กทอรี และดำเนินการเฉพาะกับไฟล์ที่มีขนาดเกินกว่าขนาดที่กำหนด เช่น คัดลอกไปยังตำแหน่งอื่น บีบอัด หรือลบไฟล์หากไฟล์นั้นมีอายุตรงตามข้อกำหนดบางประการ

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

ในส่วนของการจัดการข้อผิดพลาด หาก foreach พบข้อผิดพลาดที่ไม่ได้รับการแก้ไข มีความเป็นไปได้ที่สคริปต์ทั้งหมดจะหยุดทำงานซึ่งไม่ใช่สิ่งที่พึงปรารถนาเสมอไป วิธีปกติในการเสริมความแข็งแกร่งให้กับลูปคือการห่อตรรกะภายในไว้ในบล็อก try { ... } catch { ... }ดังนั้น หากเกิดข้อผิดพลาดกับรายการใดรายการหนึ่ง คุณสามารถบันทึกข้อผิดพลาดและดำเนินการต่อกับส่วนที่เหลือของคอลเลกชันได้โดยไม่ต้องหยุดการทำงานทั้งหมด

ข้อผิดพลาดทั่วไปและแนวทางปฏิบัติที่ดีที่สุดในการใช้ foreach

มีข้อผิดพลาดทั่วไปบางประการเมื่อทำงานร่วมกับ ลูป foreach ใน PowerShellหนึ่งในปัญหาเหล่านี้คือการใช้ชื่อตัวแปรเดียวกันในลูปซ้อนกัน ซึ่งทำให้ค่าภายในเขียนทับค่าภายนอกและสร้างผลลัพธ์ที่ไม่สามารถคาดเดาได้ วิธีแก้ก็ง่ายๆ คือ ใช้ชื่อที่แตกต่างกันสำหรับแต่ละระดับของการซ้อนกัน

ความผิดพลาดทั่วไปอีกประการหนึ่งคือ abusar de break โดยไม่คิดให้รอบคอบวิธีนี้ทำให้ลูปหยุดทำงานก่อนที่จะประมวลผลคอลเลกชันทั้งหมด ทั้งๆ ที่ตั้งใจไว้เพียงแค่ข้ามบางองค์ประกอบเท่านั้น ในหลายกรณี continue วิธีนี้เหมาะสมกว่า เพราะช่วยให้คุณข้ามขั้นตอนการทำงานบางส่วนได้โดยไม่ต้องออกจากลูปโดยสมบูรณ์

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

สำหรับแนวทางปฏิบัติที่ดีโดยทั่วไปนั้น มักจะแนะนำให้ปฏิบัติตามดังนี้ ใช้ ForEach-Object สำหรับข้อมูลที่เข้ามาผ่านทางไปป์ไลน์โดยรักษาความอ่านง่ายของเนื้อหาลูปให้มากที่สุดโดยใช้ฟังก์ชันเสริม และใช้การเว้นวรรคและคำอธิบายประกอบที่สม่ำเสมอเพื่ออำนวยความสะดวกในการบำรุงรักษาสคริปต์ในระยะยาว

เรียนรู้การใช้งาน foreach รูปแบบต่างๆ และตัวเลือกการทำงานแบบขนานใน PowerShell อย่างเชี่ยวชาญ ตั้งแต่... ForEach-Object -Parallel y Start-ThreadJob แม้แต่คนโบราณ foreach -Parallel ในเวิร์กโฟลว์ คุณสามารถ ออกแบบสคริปต์ได้เร็วขึ้นและมีประสิทธิภาพมากขึ้นโดยในแต่ละกรณี คุณควรเลือกเองว่าสนใจให้ความสำคัญกับประสิทธิภาพ หน่วยความจำ ลำดับการแสดงผล หรือความเรียบง่ายของโค้ดมากกว่าที่จะจำกัดตัวเองอยู่แค่ลูปแบบลำดับดั้งเดิมเสมอไป

PowerShell เทียบกับ CMD: ข้อดีและข้อเสีย-0
บทความที่เกี่ยวข้อง:
PowerShell เทียบกับ CMD: ความแตกต่าง ข้อดี และเมื่อใดจึงควรใช้