Search code examples
c#.netwinformsfilesystemwatcher

High cpu usage Windows forms


Relatively new to c#. I made a windows form that monitors for changes to a change in a file. The program takes up 30% of my CPU and I would like to make it run a little lighter. After running the diagnostic session, I can see that Run() is using almost half of the program's resources. Is there a way I can optimize this?

static void Run()
{
    using (FileSystemWatcher watcher = new FileSystemWatcher())
    {
        watcher.Path = Path.GetDirectoryName(path);
        watcher.Filter = Path.GetFileName(path);

        watcher.Changed += OnChanged;
        watcher.Renamed += OnRenamed;

        watcher.EnableRaisingEvents = true;

        Debug.WriteLine("Running Reader");
        while (!cts.Token.IsCancellationRequested) ;
    }
}

Here is my CPU usage.

CPU usage

My script to close the thread is also pretty heavy using almost 30%

static CancellationTokenSource cts = new CancellationTokenSource();

private async void buttonRun_Click(object sender, EventArgs e)
{
    buttonRun.Enabled = false; // Disable the button to prevent multiple clicks

    listBoxStatus.Items.Add($"Line Reader Started! \t Time: {DateTime.Now}");
    listBoxStatus.Items.Add("");

    status = "Running";
    statusApplier();

    try
    {
        await Task.Run(() =>
        {
            LogApplicationStart();
            LoadComparisonFileLines();
            Run();
        }, cts.Token);
    }
    catch (OperationCanceledException)
    {
        listBoxStatus.Items.Add($"Task was cancelled! \t Time: {DateTime.Now}");
    }
    catch (Exception ex) // Catch any other exceptions
    {
        listBoxStatus.Items.Add($"An error occurred: {ex.Message}");
    }
    finally
    {
        cts.Dispose(); // Dispose the CancellationTokenSource
        cts = new CancellationTokenSource(); // Reset the token source
        buttonRun.Enabled = true; // Enable the button after the task is completed or if an error occurs

        if (listBoxStatus.Items.Count > 0 && listBoxStatus.Items[listBoxStatus.Items.Count - 1].ToString().Contains("Change"))
        {
            listBoxStatus.Items.Add("");
        }

        listBoxStatus.Items.Add($"Line Reader Ended! \t Time: {DateTime.Now}");
        listBoxStatus.Items.Add("");

        status = "Stopped";
        statusApplier();

        LogApplicationEnd();
    }
}

private void buttonStop_Click(object sender, EventArgs e)
{
    cts.Cancel(); // Cancel the task
}

I greatly appreciate any help. Thanks

I do not know how to use FileSystemWatcher more efficiently than I am already using it


Solution

  • The culprit causing high CPU usage is the while loop, and in fact, there should not be such an almost endless empty loop in the program.

    The simplest solution for your code is to replace this loop with

    cts.WaitHandle.WaitOne();
    

    But there is another issue with your code. Your logic is to use one button to start watching and another button to stop it, so you should put the finally part and the part that disposes the FileSystemWatcher in the callback of the stop button. This CancellationTokenSource is redundancy.