1

我有一个程序,它创建一个线程来搜索 WMI(Win32 类)以检查各种系统信息。现在我为每个搜索创建一个线程,但很明显,当我使用组合框并快速滚动或触发多个线程时,cpu 会出现峰值,即使在关闭表单后,发送的“命令”仍然会发送到 wmi 提供程序,从而导致 cpu秒杀了好一阵子……

问题:

在不关闭表单的情况下,限制 cpu 使用率/创建的最大线程数以防止 cpu 峰值的最佳方法是什么。(如果我关闭表单,我可以为 WMI 提供程序进程发送一个终止进程,以便停止它)。

图片:

在此处输入图像描述

代码:

namespace Admin_Helper
{
    public partial class frmHardwareInformation : Form
    {
        public frmHardwareInformation()
        {
            InitializeComponent();
        }

        string searchQuery;

        private void cmbItemList_SelectedIndexChanged(object sender, EventArgs e)
        {
            var dctPropertyList = new Dictionary<string, string>(); //Store property name/value
            searchQuery = cmbItemList.SelectedItem.ToString(); //Search term
            new Thread(() => FindWMI(searchQuery, dctPropertyList, lstHwSearchList)).Start(); //Start thread for each search

    }

    private void FindWMI(string s, Dictionary<string, string> dct, ListView listView)
    {
        try
        {
            ManagementObjectSearcher moSearcher = new ManagementObjectSearcher("select * from " + s);

            Invoke(new MethodInvoker(() =>
                {
                    listView.Items.Clear(); //Clear items to prevent endless list
                }));

            foreach (ManagementObject moObject in moSearcher.Get())
            {
                if (moObject != null) //Gives errors if I don't check for null's..
                {
                    foreach (PropertyData propData in moObject.Properties)
                    {
                        if (propData.Value != null && propData.Value.ToString() != "" && propData.Name != null && propData.Name != "") //More prevention of errors..
                            dct[propData.Name] = propData.Value.ToString();

                    }
                }
            }

            foreach (KeyValuePair<string, string> listItem in dct)
            {
                Invoke(new MethodInvoker(() =>
                {
                    listView.Items.Add(listItem.Key).SubItems.Add(listItem.Value);
                    Application.DoEvents();
                }));
            }
        }
        catch (Exception) { } //Mostly catches invalid searches nothing too bad so far
    }
}

}

编辑:包括代码更改

*在表单关闭、创建列表和调用整个更新时添加了 1x 的杀戮过程。

private void FindWMI(string s, Dictionary<string, string> dct, ListView listView)
    {

        try
        {
            List<ListViewItem> itemsList = new List<ListViewItem>();

            ManagementObjectSearcher moSearcher = new ManagementObjectSearcher("select * from " + s);
            Invoke(new MethodInvoker(() =>
            {
              listView.Items.Clear();
            }));

            foreach (ManagementObject moObject in moSearcher.Get())
            {
                if (moObject != null)
                {
                    foreach (PropertyData propData in moObject.Properties)
                    {
                        if (propData.Value != null && propData.Value.ToString() != "" && propData.Name != null && propData.Name != "")
                            dct[propData.Name] = propData.Value.ToString();
                    }
                }
            }
            foreach (KeyValuePair<string, string> listItem in dct)
            {
                ListViewItem lstItem = new ListViewItem(listItem.Key);
                lstItem.SubItems.Add(listItem.Value);
                itemsList.Add(lstItem);
            }

            Invoke(new MethodInvoker(() =>
            {
                listView.Items.AddRange(itemsList.ToArray());
            }));
        }
        catch (Exception) { }
    }

    private void frmHardwareInformation_FormClosed(object sender, FormClosedEventArgs e)
    {
        foreach (System.Diagnostics.Process myProc in System.Diagnostics.Process.GetProcesses())
        {
            if (myProc.ProcessName == "WmiPrvSE")
            {
                myProc.Kill();
            }
        }
    }
4

1 回答 1

2

为了提高性能,您绝对应该避免在循环中调用 Control.Invoke()。您可以将整个循环包装在 Control.Invoke() 中,或者更好的是,创建要显示的项目列表,然后在单个 Control.Invoke() 调用中更新您的控件。如果您通过在非 GUI 线程上执行项目来实现对项目的进一步过滤,这将允许您避免性能损失。

此外,您不需要在那里调用 Application.DoEvents() 。

下面是我的意思的示例,即创建一个项目列表并稍后将它们添加到控件中:

var itemsToAdd = new List<ListViewItem>();
foreach (KeyValuePair<string, string> listItem in dct)
{
    ListViewItem item = new ListViewItem(listItem.Key);
    item.SubItems.Add(listItem.Value);
    itemsToAdd.Add(item);
}

Invoke(new MethodInvoker(() =>
{
    listview.Items.AddRange(itemsToAdd);
}));
于 2013-01-30T23:58:32.547 回答