Search code examples
c#winformstimerparallel.foreach

Using Timer to measure Parallel.ForEach progress pauses unexpectedly


I'm using Parallel.ForEach for the first time, where I'm processing files; in the context of a WinForms app.

As per guidance from other threads on this coding problem (Parallel.ForEach progress reporting) I have a public (int) counter property on my class which contains the parallel code, and it's successfully updating; I also have a Timer on my Form that periodically reads the counter.

The issue is that when I execute the parallel code the visible progress updating appears to stop, and then starts as soon as the parallel code is complete.

FYI - I'm calling the parallel code directly - that is, not through a background worker or async method.


Solution

  • If you are calling Parallel.ForEach() from your UI thread (lacking a code example, there's no way for us to know for sure what's happening), then the fact that that method stops and waits for all the processing to complete will prevent your UI thread from doing any other work, including a) allowing the timer event from being processed, and b) allowing the UI to be updated even if the timer even were processed.

    One possible approach would be to wrap the call of Parallel.ForEach() in a call to Task.Run(). For example:

    private async void button1_Click(object sender, EventArgs e)
    {
        // some stuff
    
        await Task.Run(() => Parallel.ForEach(...));
    
        // some other stuff
    }
    

    Alternatively, you could just execute the whole thing as individual tasks:

    private async void button1_Click(object sender, EventArgs e)
    {
        // some stuff
    
        List<Task> tasks = new List<Task>();
    
        foreach (...)
        {
            tasks.Add(Task.Run(() => ...));
        }
    
        await Task.WhenAll(tasks);
    
        // some other stuff
    }
    

    (The above examples leave out specifics, since without a code example in the question there's no way to know what would actually go there).

    Either approach should free up your UI thread to handle the progress updating while the processing goes on.