Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

set priority for Parallel.For loop

Ok, here's the situation: My main/UI thread (call it Thread1) is used for acquiring a batch of images from a phsycial document scanner. When a batch has been acquired, a separate "background" thread (call it Thread2) starts up to process and save the images from that batch.

Thread2 (the "background" thread) is using a Parallel.For loop which reduces the image processing/saving time by 70% over a normal For loop. However, it also appears to be maxing out all of my processors so that Thread1 can not start acquiring any more images until the Parallel.For loop completes.

Is there a way to "limit" a Parallel.For loop so that it does not max out my processors? Or to set the processing priority? I tried setting Thread2.Priority = ThreadPriority.Lowest, but this does not appear to affect the loop. Or am I misunderstanding how a Parallel.For loop works? Is it blocking Thread1 somehow?

Here is how I call the Thread2 from a method in Thread1.

public void SaveWithSettings(bool save) // method in Thread1
{
    ....
    Thread thr = new Thread(ThreadWork); // creating new thread (Thread 2)
    thr.Priority = ThreadPriority.Lowest; // does nothing?
    thr.Start(new SaveContainer(sc)); // pass a copy as paramater

    // misc stuff to make scanning possible again
    numBgw++;
    twain.RemoveAllImages(); // clear images
    imagelist.Clear(); // clear imagelist images
    .... // etc. this all appears to process fine while Thread2 is processing
}

Here is my ThreadWork method:

private void ThreadWork(object data) // executing in Thread2
{
    SaveContainer sc = data as SaveContainer; // holds images

    bool[] blankIndex = new bool[sc.imagelist.Count]; // to use in Parallel.For loop
    for (int i = 0; i < sc.imagelist.Count; i++)
        blankIndex[i] = false; // set default value to false (not blank)

    Parallel.For(0, sc.imagelist.Count, i => // loop to mark blank images
    {
        bool x = false; // local vars make loop more efficient
        x = sc.IsBlankImage((short)i); // check if image at index i is blank
        blankIndex[i] = x; // set if image is blank
    }
    .... // other image processing steps
}
like image 376
fancypants Avatar asked Oct 26 '12 14:10

fancypants


2 Answers

public static void PriorityParallelForeach<T>(this IEnumerable<T> source, Action<T> action, ThreadPriority threadPriority, int? maxDegreeOfParallelism = null)
   {
       if (maxDegreeOfParallelism == null || maxDegreeOfParallelism<1)
       {
           maxDegreeOfParallelism = Environment.ProcessorCount;
       }

       var blockingQueue = new BlockingCollection<T>(new ConcurrentQueue<T>(source));
       blockingQueue.CompleteAdding();

        var tasks = new List<Task>() ;

        for (int i = 0; i < maxDegreeOfParallelism; i++)
        {
            tasks.Add(Task.Factory.StartNew(() =>
             {
                 while (!blockingQueue.IsCompleted)
                 {
                     T item;
                     try
                     {
                         item = blockingQueue.Take();
                     }
                     catch (InvalidOperationException)
                     {
                         // collection was already empty
                         break;
                     }

                     action(item);
                 }
             }, CancellationToken.None,
                  TaskCreationOptions.None,
                  new PriorityScheduler(threadPriority)));
        }

        Task.WaitAll(tasks.ToArray());

   }

Or just:

Parallel.ForEach(testList, item =>
            {

                var priviousePrio = Thread.CurrentThread.Priority;
                // Set your desired priority
                Thread.CurrentThread.Priority = ThreadPriority.Lowest;

                TestCalc(item);

                //Reset priviouse priority of the TPL Thread
                Thread.CurrentThread.Priority = priviousePrio;
            });
like image 70
Andreas Avatar answered Nov 16 '22 02:11

Andreas


Is there a way to "limit" a Parallel.For loop so that it does not max out my processors?

Yes, you can add an Options with MaxDegreeOfParallelism=N.

Or to set the processing priority?

No. It is a ThreadPool (borrowed) thread. Don't change its properties. Actually it's a bunch of pool threads.

Or am I misunderstanding how a Parallel.For loop works? Is it blocking Thread1 somehow?

Yes, from the outside Parallel.For(...) is a blocking call. So run it on a separate Task or Backgroundworker, not from the main thread.

like image 29
Henk Holterman Avatar answered Nov 16 '22 02:11

Henk Holterman