You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ReactiveUI:如何实现进程内存监控中ReactiveList的周期性刷新

嘿,作为Rx的新手,你这个需求简直是Rx的典型应用场景啊!定时异步更新、后台线程处理、自动管理订阅生命周期,Rx都能帮你优雅搞定。我来给你一步步拆解实现方案:

核心思路

我们可以利用Rx的Observable.Interval生成定时信号,结合线程调度器把监控逻辑放到后台执行,再切换回UI线程更新DataGrid。同时通过订阅的IDisposable对象,轻松实现复选框勾选/取消时的启停控制,还能自然处理进程退出的异常情况。

具体实现步骤
  • 绑定复选框的勾选/取消事件,用来启动和停止Rx监控序列
  • 用Observable.Interval创建200ms间隔的触发信号,通过SubscribeOn指定后台线程池执行监控逻辑
  • 每次触发时,遍历当前监控的进程,更新内存占用,同时过滤掉已退出的进程
  • 用ObserveOn把结果切换回UI线程,安全更新DataGrid的数据源
关键代码示例(以WPF为例)
using System.Reactive.Linq;
using System.Reactive.Concurrency;
using System.Diagnostics;
using System.Windows;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;

// 进程信息模型:必须实现INotifyPropertyChanged,让UI自动更新
public class ProcessInfo : INotifyPropertyChanged
{
    private int _processId;
    private string _processName;
    private long _memoryUsage;

    public int ProcessId
    {
        get => _processId;
        set { _processId = value; OnPropertyChanged(); }
    }

    public string ProcessName
    {
        get => _processName;
        set { _processName = value; OnPropertyChanged(); }
    }

    public long MemoryUsage
    {
        get => _memoryUsage;
        set { _memoryUsage = value; OnPropertyChanged(); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

// 窗口ViewModel或后台代码
public class MainWindowViewModel : INotifyPropertyChanged
{
    private IDisposable _monitorSubscription;
    public ObservableCollection<ProcessInfo> MonitoredProcesses { get; } = new();

    // 复选框勾选事件处理
    public void OnMonitorChecked()
    {
        // 初始加载目标进程(这里可以根据你的需求筛选,比如只监控特定名称的进程)
        var initialProcesses = Process.GetProcesses()
            .Where(p => !string.IsNullOrWhiteSpace(p.ProcessName))
            .Select(MapToProcessInfo)
            .ToList();

        // 初始化UI数据源
        foreach (var proc in initialProcesses)
        {
            MonitoredProcesses.Add(proc);
        }

        // 创建Rx监控序列
        _monitorSubscription = Observable.Interval(TimeSpan.FromMilliseconds(200))
            .SubscribeOn(TaskPoolScheduler.Default) // 后台线程执行监控逻辑
            .Select(_ => UpdateProcessMemory()) // 每次间隔触发时更新内存
            .ObserveOn(Dispatcher.CurrentDispatcher) // 切回UI线程更新数据源
            .Subscribe(updatedList =>
            {
                // 更新现有进程的内存
                foreach (var updatedProc in updatedList)
                {
                    var target = MonitoredProcesses.First(p => p.ProcessId == updatedProc.ProcessId);
                    target.MemoryUsage = updatedProc.MemoryUsage;
                }

                // 移除已退出的进程
                var exitedIds = MonitoredProcesses.Select(p => p.ProcessId).Except(updatedList.Select(p => p.ProcessId));
                foreach (var id in exitedIds.ToList())
                {
                    var exitedProc = MonitoredProcesses.First(p => p.ProcessId == id);
                    MonitoredProcesses.Remove(exitedProc);
                }
            },
            error =>
            {
                // 处理异常(比如日志记录或弹窗提示)
                MessageBox.Show($"监控出错:{error.Message}");
            });
    }

    // 复选框取消事件处理
    public void OnMonitorUnchecked()
    {
        // 取消订阅,停止监控
        _monitorSubscription?.Dispose();
        _monitorSubscription = null;
        // 清空数据源
        MonitoredProcesses.Clear();
    }

    // 辅助方法:将Process映射为ProcessInfo
    private ProcessInfo MapToProcessInfo(Process process)
    {
        return new ProcessInfo
        {
            ProcessId = process.Id,
            ProcessName = process.ProcessName,
            MemoryUsage = process.WorkingSet64 / 1024 / 1024 // 转换为MB
        };
    }

    // 后台更新进程内存,过滤已退出的进程
    private List<ProcessInfo> UpdateProcessMemory()
    {
        var updatedList = new List<ProcessInfo>();
        foreach (var procInfo in MonitoredProcesses.ToList())
        {
            try
            {
                using var process = Process.GetProcessById(procInfo.ProcessId);
                procInfo.MemoryUsage = process.WorkingSet64 / 1024 / 1024;
                updatedList.Add(procInfo);
            }
            catch (ArgumentException)
            {
                // 进程已退出,跳过该进程
                continue;
            }
        }
        return updatedList;
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
关键注意事项
  • 线程安全:必须用SubscribeOn把监控逻辑放到后台线程,ObserveOn切回UI线程,避免UI卡顿和跨线程操作异常
  • 订阅管理:一定要保存IDisposable对象,取消勾选时调用Dispose(),防止内存泄漏
  • 进程退出处理:捕获ArgumentException(通过进程ID找不到进程时抛出),自动过滤已退出的进程
  • UI自动更新:进程模型必须实现INotifyPropertyChanged,这样DataGrid能自动刷新内存占用,不用手动重绘整个列表
  • WinForms适配:如果是WinForms项目,把ObserveOn(Dispatcher.CurrentDispatcher)换成ObserveOn(ControlScheduler.FromCurrentSynchronizationContext())即可

内容的提问来源于stack exchange,提问作者BertAR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:40:08