質問

I have a program that creates a thread to search the WMI (Win32 classes) to check for all kinds of system information. Now I create a thread for each search, but obviously when I use my combobox and quickly scroll or get to trigger multiple threads the cpu will spike, and even after closing the form the "commands" sent still go to the wmi provider causing a cpu spike for quite a while...

Question:

What would be the best way to limit the cpu usage / max threads created to prevent cpu spikes without closing the form. (I can send a kill process for the WMI provider process if I close the form, so that would stop it).

Image:

enter image description here

Code:

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
    }
}

}

EDIT: Included code changes

*Added killing processes on form closing, creating a list and invoking the whole update in 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();
            }
        }
    }
役に立ちましたか?

解決

To improve performance you should definitely avoid calling Control.Invoke() within your loops. You could wrap your entire loop in a Control.Invoke() instead or, even better, create a list of items to display and then update your control in a single Control.Invoke() invocation. This would allow you to avoid performance hits if you implemented further filtering on items by performing them on the non-GUI thread.

Also, you shouldn't need the Application.DoEvents() call in there.

Here's an example of what I mean by creating a list of items and adding them to the control later:

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);
}));
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top