C#异步调用PowerShell获取多厂商显卡进程GPU使用率实现问询
C# 异步调用PowerShell获取自身进程GPU使用率的正确实现
前置依赖
首先你需要安装PowerShell SDK的NuGet包:System.Management.Automation,选择和你项目目标框架匹配的版本即可。
问题原因
你原有代码里BeginInvoke()返回的是IAsyncResult类型的异步操作句柄,不是PowerShell的执行结果,直接调用ToString()只会输出类型名称,自然无法拿到GPU使用率数值。
推荐实现方案(async/await 无阻塞)
我们直接把当前进程ID传入PowerShell脚本,避免脚本写死进程名的问题,同时用异步等待的方式获取结果,完成后再更新UI:
using System; using System.Diagnostics; using System.Management.Automation; using System.Threading.Tasks; // 异步获取GPU使用率的方法 public async Task<string> GetCurrentProcessGpuUsageAsync() { // 直接内嵌PowerShell脚本,替换进程ID为当前进程ID,避免读取外部文件 string script = $@" $p = Get-Process -Id {Process.GetCurrentProcess().Id}; ((Get-Counter ""\GPU Engine(pid_$($p.id)*engtype_3D)\Utilization Percentage"").CounterSamples | where CookedValue).CookedValue | foreach {{Write-Output ""$([math]::Round($_,1))%""}} "; using (PowerShell ps = PowerShell.Create()) { ps.AddScript(script); // 异步调用PowerShell并等待结果 var results = await ps.InvokeAsync(); // 处理执行错误 if (ps.HadErrors) { foreach (var error in ps.Streams.Error) { Debug.WriteLine(error.ToString()); } return "获取失败"; } // 返回第一个有效结果 if (results.Count > 0) { return results[0].BaseObject.ToString(); } return "0%"; } }
UI更新调用示例
因为UI控件只能在UI线程更新,调用的时候根据你用的UI框架做对应处理即可:
WinForm 示例
private async void UpdateGpuInfoBtn_Click(object sender, EventArgs e) { string gpuUsage = await GetCurrentProcessGpuUsageAsync(); // 直接赋值即可,await会自动回到UI线程上下文 gpuinfobox.Text = gpuUsage; }
WPF 示例
和WinForm调用逻辑一致,await后直接赋值给控件属性即可。
可选回调式实现(不使用async/await)
如果你需要用传统回调的方式处理,也可以用BeginInvoke加回调的写法:
public void GetCurrentProcessGpuUsageAsync(Action<string> callback) { string script = $@" $p = Get-Process -Id {Process.GetCurrentProcess().Id}; ((Get-Counter ""\GPU Engine(pid_$($p.id)*engtype_3D)\Utilization Percentage"").CounterSamples | where CookedValue).CookedValue | foreach {{Write-Output ""$([math]::Round($_,1))%""}} "; PowerShell ps = PowerShell.Create(); ps.AddScript(script); ps.BeginInvoke(null, null, ar => { try { var results = ps.EndInvoke(ar); string res = ps.HadErrors || results.Count == 0 ? "获取失败" : results[0].BaseObject.ToString(); // 回调返回结果,更新UI需要主动调度到UI线程 this.Invoke((Action)(() => gpuinfobox.Text = res)); } finally { ps.Dispose(); } }, null); }
内容的提问来源于stack exchange,提问作者MrBi
相关产品推荐
相关产品推荐

