วิธีดำเนินการ Powershell Pipeline แบบอะซิงโครนัส

วิธีทำให้ Powershell ดำเนินการไปป์ไลน์แบบอะซิงโครนัสแทนที่จะเป็น 'ตามลำดับ'

ตัวอย่างเพื่อแสดงสิ่งนี้:

Function PipeDelay($Name, $Miliseconds){
    Process {
        Sleep -miliseconds $Miliseconds
        Write-Host "$Name : $_"
        $_        
    }
}

1..7 | PipeDelay Fast 100 | PipeDelay Slow 300 | PipeDelay Slowest 900

ผลลัพธ์ในทั้ง ISE และ PowerShell มีดังต่อไปนี้:

Fast : 1
Slow : 1
Slowest : 1
1
Fast : 2
Slow : 2
Slowest : 2
2
Fast : 3
Slow : 3
Slowest : 3
3
...

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

Fast    :  1                         2                         3
Slow    :    1---1                     2---2                     3---3
Slowest :          1---------------1         2---------------2         3-----...

เป็นไปได้หรือไม่กับการตั้งค่า/ตัวแปรสภาพแวดล้อม/อื่นๆ เพื่อทำให้ไปป์ไลน์ทำงานอย่างอิสระ/อะซิงโครนัส? อาจมีการตั้งค่าเกี่ยวกับขนาดบัฟเฟอร์ไปป์ไลน์ ฯลฯ ? เพื่อให้การดำเนินการมีลักษณะดังนี้:

Fast    :  1 2 3 4 5 6 7
Slow    :    1---1 2---2 3---3 4---4 5---5 6---6 7---7
Slowest :          1---------------1 2---------------2 3-----...

หมายเหตุ

ฉันคิดว่าเป็นเพราะโหมด STA/MTA ฉันไม่เข้าใจพวกเขาทั้งหมด แต่ผลลัพธ์เดียวกันใน ISE (STA) / Powershell Shell (MTA) ดูเหมือนว่าจะกำจัดโหมด STA/MTA เป็นสาเหตุ

นอกจากนี้ ฉันคิดว่า Write-Host เป็นปัญหาที่บังคับให้ไปป์ไลน์ประมวลผลตามลำดับ แต่แม้ว่าฉันจะแทนที่ Write-Host ด้วย New-Event การประมวลผลตามลำดับก็ยังคงมีผลอยู่


person tkokasih    schedule 14.10.2014    source แหล่งที่มา
comment
สิ่งที่คุณถามนั้นไม่ใช่เรื่องง่าย ข้อดีอย่างหนึ่งของไปป์ไลน์ก็คือไม่ใช่ว่าวัตถุทั้งเจ็ดจะอยู่ในหน่วยความจำในคราวเดียว อย่างไรก็ตาม วิธีที่คุณแสดงทั้งเจ็ดจะถูกแคชอย่างรวดเร็วและจะไม่ได้รับการแก้ไขจนกว่าจะเสร็จสิ้นช้าที่สุด คุณจะต้องสร้างคันเร่งในไปป์ไลน์ ดังนั้นหากคุณทำงานกับออบเจ็กต์ขนาด 5GB+ คุณจะไม่พัฒนาหน่วยความจำเกินเลย load-from-file | do-something-fast | do-something-slow | do-something-slowest | save-to-file   -  person Gregor y    schedule 30.07.2019
comment
ใช่ ตกลงกันในประเด็นที่ว่าไปป์ไลน์จำเป็นต้องมีขีดจำกัดบางประการ ไม่ว่าจะชัดเจนหรือโดยปริยาย (ค่าเริ่มต้น ค่าคงที่) ดังนั้นจึงมีคำถาม: อาจมีการตั้งค่าเกี่ยวกับขนาดบัฟเฟอร์ไปป์ไลน์ ฯลฯ ? ตอนนี้ดูเหมือนว่า Powershell จะมี Foreach Parallel แต่มีเฉพาะในเวิร์กโฟลว์เท่านั้น   -  person tkokasih    schedule 31.07.2019


คำตอบ (1)


ฉันไม่คิดว่าคุณจะสามารถใช้ประโยชน์จากไปป์ไลน์ในลักษณะอะซิงโครนัสในแบบที่คุณต้องการโดยไม่ต้องเสียค่าใช้จ่ายแพงกับการใช้ทรัพยากร ฉันพยายามจับภาพจิตวิญญาณของสิ่งที่คุณพยายามทำให้สำเร็จ แต่ในวิธีที่แตกต่างออกไป ฉันใช้ตัวอย่างที่แตกต่างออกไปเล็กน้อยเพื่อแสดงให้เห็นว่า [Automation.PowerShell] Async ทำงานอย่างไร

#1. You have a list of room requests you want to process in a function.  TimeToClean was added as a controllable thread block.
$roomsToClean = @( ([psCustomObject]@{Name='Bedroom';TimeToClean=2}),
                   ([psCustomObject]@{Name='Kitchen';TimeToClean=5}),
                   ([psCustomObject]@{Name='Bathroom';TimeToClean=3}),
                   ([psCustomObject]@{Name='Living room';TimeToClean=1}),
                   ([psCustomObject]@{Name='Dining room';TimeToClean=1}),
                   ([psCustomObject]@{Name='Foyier';TimeToClean=1})
                )


#2. We will clean three rooms and return a custom PowerShell object with a message.
Function Clean-Room{
     param([string]$RoomName,[int]$Seconds)

      Sleep -Seconds $Seconds
      Write-Output [psCustomObject] @{Message= "The robot cleaned the $RoomName in $Seconds seconds."}    
}


#3. Executing this list synchronously will result in an approximate 13 second runtime.
Write-Host "===== Synchronous Results =====" -ForegroundColor Green

$stopwatch =  [system.diagnostics.stopwatch]::StartNew()
foreach($item in $roomsToClean){
    $obj = Clean-Room $item.Name $item.TimeToClean
    Write-Output $obj.Message
}

$stopwatch.Stop()
Write-Host "Execution time for synchronous function was $($stopwatch.Elapsed)." -ForegroundColor Green


#4. Now let's run this function asynchronously for all of these items. Expected runtime will be approximately 5 seconds.


#=============== Setting up an ansynchronous powerShell Automation object and attaching it to a runspace.
#Many [Automation.PowerShell] objects can be attached to a given Runspace pool and the Runspace pool will manage queueing/dequeueing of each PS object as it completes.

#Create a RunSpace pool with 5 runspaces.  The pool will manage the 
#Many PowerShell autom
$minRunSpaces = 2
$maxRunsSpaces = 5
$runspacePool = [RunspaceFactory]::CreateRunspacePool($minRunSpaces, $maxRunsSpaces)    
$runspacePool.ApartmentState = 'STA'   #MTA = Multithreaded apartment  #STA = Singl-threaded apartment.
$runspacePool.Open()  #runspace pool must be opened before it can be used.

#For each room object, create an [Automation.PowerShell] object and attach it to the runspace pool.
#Asynchronously invoke the function for all objects in the collection.
$ps_collections = foreach($room in $roomsToClean){
                    try{

                    $ps = [System.Management.Automation.PowerShell]::Create() 
                    $ps.RunspacePool = $runspacePool

                    #Add your custom functions to the [Automation.PowerShell] object.
                    #Add argument with parameter name for readability. You may just use AddArgument as an alternative but know your positional arguments.

                    [void] $ps.AddScript(${function:Clean-Room})
                    [void] $ps.AddParameter('RoomName',$room.Name)        #Add parameterName,value
                    [void] $ps.AddParameter('Seconds',$room.TimeToClean)  #Add parameterName,value

                    #extend the ps management object to include AsyncResult and attach the AsyncResult object for receiving results at a later time.
                    $ps | Add-Member -MemberType NoteProperty -Name 'AsyncResult' -Value $ps.BeginInvoke()  #invoke asynchronously
                    $ps | Add-Member -MemberType ScriptMethod -Name 'GetAsyncResult' -Value {$this.EndInvoke($this.AsyncResult) } -PassThru
                    }
                    catch{
                        throw $_  #handle custom error here.
                    }
                }




#After the function has been asynchronously called for all room objects, Grab results from asynchronous function calls.
Write-Host "===== Asynchronous Results =====" -ForegroundColor Green
$stopwatch =  [system.diagnostics.stopwatch]::StartNew()
foreach($ps in $ps_collections){
    $obj = $ps.GetAsyncResult()
    [void] $ps.Dispose()  #dispose of object after use.
    Write-Output $obj.Message
}

$stopwatch.Stop()
Write-Host "Execution time for asynchronous function was 
$($stopwatch.Elapsed)." -ForegroundColor Green

#Runspace cleanup.
If($runspacePool){
    [void] $runspacePool.Close()
    [void] $runspacePool.Dispose()
}

เวลาผลลัพธ์จะแตกต่างกันเล็กน้อยแต่ควรมีลักษณะคล้ายกับสิ่งนี้:

===== Synchronous Results =====

หุ่นยนต์ทำความสะอาดห้องนอนภายใน 2 วินาที

หุ่นยนต์ทำความสะอาดห้องครัวใน 5 วินาที

หุ่นยนต์ทำความสะอาดห้องน้ำภายใน 3 วินาที

หุ่นยนต์ทำความสะอาดห้องนั่งเล่นภายใน 1 วินาที

หุ่นยนต์ทำความสะอาดห้องรับประทานอาหารภายใน 1 วินาที

หุ่นยนต์ทำความสะอาด Foyier ภายใน 1 วินาที

เวลาดำเนินการสำหรับฟังก์ชันซิงโครนัสคือ 00:00:13.0719157

===== Asynchronous Results =====

หุ่นยนต์ทำความสะอาดห้องนอนภายใน 2 วินาที

หุ่นยนต์ทำความสะอาดห้องครัวใน 5 วินาที

หุ่นยนต์ทำความสะอาดห้องน้ำภายใน 3 วินาที

หุ่นยนต์ทำความสะอาดห้องนั่งเล่นภายใน 1 วินาที หุ่นยนต์ทำความสะอาดห้องรับประทานอาหารภายใน 1 วินาที

หุ่นยนต์ทำความสะอาด Foyier ภายใน 1 วินาที

เวลาดำเนินการสำหรับฟังก์ชันอะซิงโครนัสคือ 00:00:04.9909951

person binarySalt    schedule 21.04.2018