为Parallel.For循环设置优先级

fan*_*nts 6 c# task-parallel-library

好的,情况如下:我的主要/ UI线程(称之为Thread1)用于从phsycial文档扫描程序中获取一批图像.获取批次后,会启动一个单独的"后台"线程(称为Thread2)来处理并保存该批次中的图像.

Thread2("后台"线程)使用Parallel.For循环,在正常For循环中将图像处理/节省时间减少70%.但是,它似乎也最大化了我的所有处理器,因此在Parallel.For循环完成之前,Thread1无法再开始获取任何图像.

有没有办法"限制"一个Parallel.For循环,以便它不会最大化我的处理器?或者设置处理优先级?我尝试过设置Thread2.Priority = ThreadPriority.Lowest,但这似乎不会影响循环.或者我误解了Parallel.For循环是如何工作的?是以某种方式阻止Thread1?

这是我如何从Thread1中的方法调用Thread2.

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
}
Run Code Online (Sandbox Code Playgroud)

这是我的ThreadWork方法:

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
}
Run Code Online (Sandbox Code Playgroud)

And*_*eas 5

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());

   }
Run Code Online (Sandbox Code Playgroud)

要不就:

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;
            });
Run Code Online (Sandbox Code Playgroud)


fan*_*nts 1

好吧,我明白了!我只是发布此内容以防万一有人无意中发生这种情况......

事实证明,该Parallel.For线程并未阻塞 Thread1(是的,你没问题)。然而,当循环正在运行时,Thread1 中的一个对象试图Thread从Thread1 中获取一个新对象ThreadPool,因此发生了“延迟”。我使用的是第 3 方 SDK,它允许我与 TWAIN 界面进行交互,并且有一个选项ScanInNewThread = true可以在每次用户开始新扫描时尝试获取新线程(这是在循环运行时发生的)。我能够更改此设置,以便在整个应用程序会话中使用单个(但仍然是单独的)线程,而不是为每个扫描批次抓取一个新线程,然后砰的一声,不再有明显的延迟。

SO - 这个故事的寓意:

现有线程应该仍然“正常”运行(调用循环的线程除外Parallel.For),只要它们在ThreadPool循环进行时不尝试从循环中获取更多线程即可。