【问题标题】:How to set Low I/O ("background") priority in Powershell如何在 Powershell 中设置低 I/O(“后台”)优先级
【发布时间】:2020-05-03 14:35:30
【问题描述】:

this powershell script 可以将进程的优先级从“空闲”设置为“实时”,但有些工具提供了另一个优先级,甚至会降低进程的优先级:

如何在 Powershell 中设置?

【问题讨论】:

  • 答案可能在other responses there 之一中 - 查看该代码标题中的优先级名称并注意至少一个如何映射到您找到的答案。然后尝试其他的并查看结果。
  • 不,恐怕不是这样。首先,因为我已经测试了所有这些。其次,如果您尝试设置 priority from Windows task manager 本身,它不提供“背景”选项,这让我相信它不是与设置这些不同级别的所有其他选项一起使用的选项优先事项。设置一些 I/O/内存优先级,而不是进程优先级,这绝对是不同的东西。
  • Here is a SO question on how to do it in C#,也许您可​​以将该问题的答案移植到 Powershell 并将您自己的答案发布给其他人。
  • 有一个名为 Process Hacker 的免费程序(类似于 Process Explorer),它可以让您将 IO 优先级与 CPU 优先级分开设置。 github.com/processhacker/processhacker

标签: powershell process powershell-3.0


【解决方案1】:

我不清楚是否可以设置 IO 优先级。 SetProcessInformation() 调用将 PROCESS_INFORMATION_CLASS 作为参数,并且只定义 ProcessMemoryPriority。我在使用内存优先级为 2 的任务管理器中运行 powershell 脚本时遇到问题,这让我很生气。我是 PInvoke 的新手,并在 PowerShell 中使用它,所以我可能违反了至少一个最佳实践,但下面的 sn-p 解决了我的问题。

通过 C# 加载函数的 Add-Type 东西:

Add-Type @"
using System;
using System.Runtime.InteropServices;

namespace SysWin32
{
    public enum PROCESS_INFORMATION_CLASS
    {
        ProcessMemoryPriority,
        ProcessInformationClassMax,
    }

    [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public struct MEMORY_PRIORITY_INFORMATION
    {
        public uint MemoryPriority;
    }

    public partial class NativeMethods {
        [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint="GetCurrentProcess")]
        public static extern System.IntPtr GetCurrentProcess();

        [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint="SetProcessInformation")]
        public static extern bool SetProcessInformation(System.IntPtr hProcess, PROCESS_INFORMATION_CLASS ProcessInformationClass, System.IntPtr ProcessInformation, uint ProcessInformationSize) ;
    }
}
"@

下面是使用函数的示例:

$myProcessHandle = [SysWin32.NativeMethods]::GetCurrentProcess()
$memInfo = New-Object SysWin32.MEMORY_PRIORITY_INFORMATION
$memInfo.MemoryPriority = 5
$memInfoSize = [System.Runtime.Interopservices.Marshal]::SizeOf($memInfo)
$memInfoPtr = [System.Runtime.Interopservices.Marshal]::AllocHGlobal($memInfoSize)
[System.Runtime.Interopservices.Marshal]::StructureToPtr($memInfo, $memInfoPtr, $false)
$result = [SysWin32.NativeMethods]::SetProcessInformation($myProcessHandle, [SysWin32.PROCESS_INFORMATION_CLASS]::ProcessMemoryPriority, $memInfoPtr, $memInfoSize)
$result

使用 procexp 我能够验证我的 powershell 脚本现在正在以 5 的内存优先级运行。

【讨论】:

    【解决方案2】:

    这是用于降低进程优先级的 PowerShell 单行代码:

    (get-process msosync).PriorityClass='BelowNormal'

    在此 PowerShell 上下文中,PriorityClass 的有效值可以是以下之一:Normal、Idle、High、RealTime、BelowNormal、AboveNormal

    你可以用这个单线测试结果:

    get-process msosync | Select-Object Name,PriorityClass,CPU | Format-Table -AutoSize

    【讨论】:

      【解决方案3】:

      Peter Friend's answer above 开始,我编写了一个 powershell 脚本来更新所有 3 个有问题的优先级(CPU、内存和 IO)。我会把它贴在这里,因为这是这个问题在谷歌中排名第一的结果。

      你可以像这样从 Powershell 运行它 -

      .\SetProcessPriority.ps1 -ProcessName sqlservr -CpuPriorityClass Idle -MemoryPriority 1 -IoPriority 0
      
      • CpuPriorityClass 的选项有 - Idle、BelowNormal、Normal、AboveNormal、High、Realtime
      • MemoryPriority 的选项为 1-5(将此设置为 1 模拟了当您选择 Process Explorer 的“Background”“Low I/O and Memory Priority”选项时发生的情况)
      • IoPriority 的选项为 0(非常低)、1(低)、2(正常)(将此设置为 0 模拟了当您选择 Process Explorer 的“背景”“低 I/O 和内存优先级”选项时发生的情况)

      SetProcessPriority.ps1 代码 -

      [CmdletBinding()]
      Param (
          [string]$ProcessName = "sqlservr",
          [string]$CpuPriorityClass = "Idle",
          [int]$MemoryPriority = 1,
          [int]$IoPriority = 0
      )
      
      # If you can't run, execute this first from an elevated PowerShell Prompt - set-executionpolicy remotesigned
      If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
      {   
          $arguments = "& '" + $myinvocation.mycommand.definition + "'"
          Start-Process powershell -Verb runAs -ArgumentList $arguments
          Break
      }
      
      Add-Type @"
      using System;
      using System.Runtime.InteropServices;
      
      namespace SysWin32
      {
          public enum PROCESS_INFORMATION_CLASS
          {
              ProcessMemoryPriority,
              ProcessInformationClassMax,
          }
      
          [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
          public struct PROCESS_INFORMATION
          {
              public uint Information;
          }
      
          public partial class NativeMethods {
              [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint="GetCurrentProcess", SetLastError=true)]
              public static extern System.IntPtr GetCurrentProcess();
      
              [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint="OpenProcess", SetLastError=true)]
              public static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
      
              [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint="SetProcessInformation", SetLastError=true)]
              public static extern bool SetProcessInformation(System.IntPtr hProcess, PROCESS_INFORMATION_CLASS ProcessInformationClass, System.IntPtr ProcessInformation, uint ProcessInformationSize) ;
          }
      }
      
      namespace SysWinNT
      {
          public enum PROCESS_INFORMATION_CLASS
          {
              ProcessBasicInformation,
              ProcessQuotaLimits,
              ProcessIoCounters,
              ProcessVmCounters,
              ProcessTimes,
              ProcessBasePriority,
              ProcessRaisePriority,
              ProcessDebugPort,
              ProcessExceptionPort,
              ProcessAccessToken,
              ProcessLdtInformation,
              ProcessLdtSize,
              ProcessDefaultHardErrorMode,
              ProcessIoPortHandlers,          // Note: this is kernel mode only
              ProcessPooledUsageAndLimits,
              ProcessWorkingSetWatch,
              ProcessUserModeIOPL,
              ProcessEnableAlignmentFaultFixup,
              ProcessPriorityClass,
              ProcessWx86Information,
              ProcessHandleCount,
              ProcessAffinityMask,
              ProcessPriorityBoost,
              ProcessDeviceMap,
              ProcessSessionInformation,
              ProcessForegroundInformation,
              ProcessWow64Information,
              ProcessImageFileName,
              ProcessLUIDDeviceMapsEnabled,
              ProcessBreakOnTermination,
              ProcessDebugObjectHandle,
              ProcessDebugFlags,
              ProcessHandleTracing,
              ProcessIoPriority,
              ProcessExecuteFlags,
              ProcessTlsInformation,
              ProcessCookie,
              ProcessImageInformation,
              ProcessCycleTime,
              ProcessPagePriority,
              ProcessInstrumentationCallback,
              ProcessThreadStackAllocation,
              ProcessWorkingSetWatchEx,
              ProcessImageFileNameWin32,
              ProcessImageFileMapping,
              ProcessAffinityUpdateMode,
              ProcessMemoryAllocationMode,
              ProcessGroupInformation,
              ProcessTokenVirtualizationEnabled,
              ProcessConsoleHostProcess,
              ProcessWindowInformation,
              MaxProcessInfoClass             // MaxProcessInfoClass should always be the last enum
          }
      
          public partial class NativeMethods {
              [System.Runtime.InteropServices.DllImportAttribute("ntdll.dll", EntryPoint="NtSetInformationProcess")]
              public static extern int NtSetInformationProcess(System.IntPtr hProcess, PROCESS_INFORMATION_CLASS processInformationClass, System.IntPtr ProcessInformation, uint ProcessInformationSize);
          }
      }
      "@
      
      $OverallResult = 0
      
      $Process = Get-Process $ProcessName
      $ProcessId = $Process.id
      Try
      {
          $Process.PriorityClass=$CpuPriorityClass
      }
      Catch
      {
          Write-host -BackgroundColor Black -ForegroundColor Red "Error setting process priority  - $($_.Exception.Message)"
          pause
          $OverallResult = 1
          exit $OverallResult
      }
      Write-Host -ForegroundColor Green ("Set CPU piority on {0} ({1}) to be {2}" -f $ProcessName, $ProcessId, $CpuPriorityClass)
      
      #    4096 or     0x1000 = PROCESS_QUERY_LIMITED_INFORMATION
      # 1056763 or 0x00101ffb = PROCESS_ALL_ACCESS
      $DesiredAccess = 0x00101ffb
      $InheritHandle = $false
      $hProcess = [SysWin32.NativeMethods]::OpenProcess($DesiredAccess, $InheritHandle, $ProcessId);
      $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error()
      if ($hProcess -eq 0) 
      {
          Write-Host -BackgroundColor Black -ForegroundColor Red "Failed to open Win32 process.  Error: $(([ComponentModel.Win32Exception] $LastError).Message)"
          pause
          $OverallResult = 2
          exit $OverallResult
      }
      Write-Host -ForegroundColor Green ("Successfully got handle - {0}" -f $hProcess)
      
      $memInfo = New-Object SysWin32.PROCESS_INFORMATION
      $memInfo.Information = $MemoryPriority
      $memInfoSize = [System.Runtime.Interopservices.Marshal]::SizeOf($memInfo)
      $memInfoPtr = [System.Runtime.Interopservices.Marshal]::AllocHGlobal($memInfoSize)
      [System.Runtime.Interopservices.Marshal]::StructureToPtr($memInfo, $memInfoPtr, $false)
      $result = [SysWin32.NativeMethods]::SetProcessInformation($hProcess, [SysWin32.PROCESS_INFORMATION_CLASS]::ProcessMemoryPriority, $memInfoPtr, $memInfoSize)
      $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error()
      if (!$result)
      {
          $OverallResult = 3
          Write-Host -BackgroundColor Black -ForegroundColor Red ("Failed to set memory piority on {0} ({1}) to be {2}.  Error: {3}" -f $ProcessName, $ProcessId, $MemoryPriority, ([ComponentModel.Win32Exception]$LastError).Message)
      }
      else
      {
          Write-Host -ForegroundColor Green ("Set memory piority on {0} ({1}) to be {2}." -f $ProcessName, $ProcessId, $MemoryPriority)
      }
      
      $ioInfo = New-Object SysWin32.PROCESS_INFORMATION
      $ioInfo.Information = $IoPriority
      $ioInfoSize = [System.Runtime.Interopservices.Marshal]::SizeOf($ioInfo)
      $ioInfoPtr = [System.Runtime.Interopservices.Marshal]::AllocHGlobal($ioInfoSize)
      [System.Runtime.Interopservices.Marshal]::StructureToPtr($ioInfo, $ioInfoPtr, $false)
      $result = [SysWinNT.NativeMethods]::NtSetInformationProcess($hProcess, [SysWinNT.PROCESS_INFORMATION_CLASS]::ProcessIoPriority, $ioInfoPtr, $ioInfoSize)
      $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error()
      if ($result -ne 0)
      {
          $OverallResult = 4
          Write-Host -BackgroundColor Black -ForegroundColor Red ("Failed to set IO piority on {0} ({1}) to be {2}.  Result: {3}.  Error: {4}" -f $ProcessName, $ProcessId, $IoPriority, $result, ([ComponentModel.Win32Exception]$LastError).Message)
      }
      else
      {
          Write-Host -ForegroundColor Green ("Set IO piority on {0} ({1}) to be {2}" -f $ProcessName, $ProcessId, $IoPriority)
      }
      exit $OverallResult
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-01-07
        • 1970-01-01
        • 2011-02-21
        • 1970-01-01
        • 2014-10-27
        • 2021-03-05
        • 1970-01-01
        相关资源
        最近更新 更多