代码之家  ›  专栏  ›  技术社区  ›  VA systems engineer

当所有的工作都在本地计算机上的后台工作中完成时,如何保持UI的响应性和更新进度?

  •  0
  • VA systems engineer  · 技术社区  · 7 年前

    我有一个程序可以显示 UI ,允许用户选择通过查询 Xen 池主服务器,然后为选定的虚拟机创建快照。我想在后台创建快照,这样我就可以保留 响应并更新 用户界面 随着每个快照的创建而进行。

    最初,我连接到 Xen公司 Xen公司 在中为每个选定的VM创建一次快照cmdlet 用户界面 用户界面 变得毫无反应。

    接下来,我连接到 Xen公司 start-job ( background job )每个虚拟机一次以创建虚拟机的快照。此操作失败,因为 Xen公司 在中创建的会话 线程无法传递到 (session变量的内容使其进入块,但是Xen Connect Could not find open sessions to any XenServers 错误)。

    然后,我转到 Xen公司 将主服务器池到 背景工作 . 这减慢了操作,因为建立连接需要几秒钟,而且每个虚拟机只进行一次。然而 用户界面 .

    我怎样才能保持 响应,更新 用户界面

    1 回复  |  直到 7 年前
        1
  •  0
  •   VA systems engineer    7 年前

    更新

    此解决方案允许在后台作业运行时在UI线程中获取更新,但它不能保持UI响应。看我的 对罗欣的回应如下。

    解决方法是将整个循环移动到 background job Write-Progress cmdlet来报告 UI . 使用 写入进度 此场景中的cmdlet转到 Ryan

    这里是一个简单的演示说明所有需要的部分

    cls
    
    ## Job code
    $ScriptBlockCode = 
    {
        param($items)
        $retObj = @{}
    
        try
        {
            $error.clear()
    
            for ($i = 0; $i -lt $items.Count; $i++)
            {
    
                #wait to simulate the time it takes to do work on item $i
                start-sleep -Seconds (get-random -Minimum 2 -Maximum 6)
    
                # Use Write-Progress to report the completion of each item for as long as the job runs (Can be used to updage the UI)
                # Use the -Completed argument to suppress displaying the progress bar 
                Write-Progress  -Id ($i+1) -Activity ("For UI Update: " + $items[$i] + " processing complete") -Status "Reporting" -PercentComplete ((($i+1)/$items.Count)*100) -Completed
    
                #Use a hashtable to report the status of each job. To be used in the calling code after the job status is no longer Running
                #simulate some items passing, some failing
                if ((get-random -Minimum 0 -Maximum 2) -eq 0)
                {
                    $itemRet = [PSCustomObject]@{status="FAIL";details="some error description"}
                }
                else
                {
                    $itemRet = [PSCustomObject]@{status="PASS";details=""}
                }
    
                $retObj.Add($items[$i],$itemRet)
    
            }
    
            return $retObj
        }
        catch
        {
            $itemRet = [PSCustomObject]@{status="ERROR";details=$error}
            $retObj.Add("FATAL",$itemRet)
            return $retObj
        }
    
    }
    
    cls
    
    #clean up before starting
    Get-Job -Name "UniqueJobName" -ErrorAction SilentlyContinue | Stop-Job
    Get-Job -Name "UniqueJobName" -ErrorAction SilentlyContinue | Remove-Job
    
    #simulate 5 pieces of work
    $items = @("Item A", "Item B", "Item C", "Item D", "Item E")
    
    $job = Start-Job -Name "UniqueJobName" -ScriptBlock $ScriptBlockCode -ArgumentList ($items)
    
    #loop and update UI until job is done
    
    $lastActivityId = -99
    
    While ($job.State -eq "Running")
    {
        $child = $job.ChildJobs[0]
    
        #update the UI only if progress has started and the ActivityId has not already been reported on and the Progress report is one I care about
        if ($child.Progress.Count -gt 0 -and $child.Progress[$child.Progress.Count - 1].ActivityId -ne $lastActivityId -and ($child.Progress[$child.Progress.Count - 1]).StatusDescription -eq "Reporting")
        {
            write-host "=============================="
            write-host "in progress updates"
            write-host "=============================="
            #use the progress properties, i.e., RecordType and PercentComplete to update the UI
            $child.Progress[$child.Progress.Count - 1]
    
            #store this Id so we can ignore progress until Id changes
            $lastActivityId = $child.Progress[$child.Progress.Count - 1].ActivityId
        }
    
        #period at which the UI is updated
        start-sleep -milliseconds 250
    }
    
    $retObj = Receive-Job -Name "UniqueJobName"
    
    write-host "=============================="
    write-host "receive job"
    write-host "=============================="
    
    # Because the job may finish before progress is captured 
    # for each item, use the returned values to update the UI one last time
    foreach ($key in $retObj.GetEnumerator())
    {
        "retObj=" + $key.name + " " + $key.Value.status + " " + $key.Value.details
    }
    
    #cleanup
    Get-Job -Name "UniqueJobName" | Stop-Job
    Get-Job -Name "UniqueJobName" | Remove-Job
    

    ==============================
    in progress updates
    ==============================
    
    
    ActivityId        : 1
    ParentActivityId  : -1
    Activity          : For UI Update: Item A processing complete
    StatusDescription : Reporting
    CurrentOperation  : 
    PercentComplete   : 20
    SecondsRemaining  : -1
    RecordType        : Completed
    
    ==============================
    in progress updates
    ==============================
    ActivityId        : 2
    ParentActivityId  : -1
    Activity          : For UI Update: Item B processing complete
    StatusDescription : Reporting
    CurrentOperation  : 
    PercentComplete   : 40
    SecondsRemaining  : -1
    RecordType        : Completed
    
    ==============================
    in progress updates
    ==============================
    ActivityId        : 3
    ParentActivityId  : -1
    Activity          : For UI Update: Item C processing complete
    StatusDescription : Reporting
    CurrentOperation  : 
    PercentComplete   : 60
    SecondsRemaining  : -1
    RecordType        : Completed
    
    ==============================
    in progress updates
    ==============================
    ActivityId        : 4
    ParentActivityId  : -1
    Activity          : For UI Update: Item D processing complete
    StatusDescription : Reporting
    CurrentOperation  : 
    PercentComplete   : 80
    SecondsRemaining  : -1
    RecordType        : Completed
    
    ==============================
    receive job
    ==============================
    retObj=Item D PASS 
    retObj=Item E PASS 
    retObj=Item A FAIL some error description
    retObj=Item B FAIL some error description
    retObj=Item C PASS