Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为并行设置优先级。为循环设置优先级_C#_Task Parallel Library - Fatal编程技术网

C# 为并行设置优先级。为循环设置优先级

C# 为并行设置优先级。为循环设置优先级,c#,task-parallel-library,C#,Task Parallel Library,好的,情况是这样的:我的main/UI线程(称为Thread1)用于从phsycial文档扫描仪获取一批图像。获取批处理后,将启动一个单独的“后台”线程(称为Thread2)来处理和保存该批处理中的图像 Thread2(“后台”线程)使用的是并行.For循环,与正常For循环相比,图像处理/保存时间减少了70%。但是,它似乎也耗尽了我所有的处理器,因此Thread1无法开始获取更多图像,直到Parallel.For循环完成 有没有一种方法可以“限制”一个并行。For循环,这样它就不会耗尽我的处理

好的,情况是这样的:我的main/UI线程(称为Thread1)用于从phsycial文档扫描仪获取一批图像。获取批处理后,将启动一个单独的“后台”线程(称为Thread2)来处理和保存该批处理中的图像

Thread2(“后台”线程)使用的是
并行.For
循环,与正常
For
循环相比,图像处理/保存时间减少了70%。但是,它似乎也耗尽了我所有的处理器,因此Thread1无法开始获取更多图像,直到
Parallel.For
循环完成

有没有一种方法可以“限制”一个
并行。For
循环,这样它就不会耗尽我的处理器?或者设置处理优先级?我尝试设置
Thread2.Priority=ThreadPriority.lower
,但这似乎不会影响循环。还是我误解了
并行For
循环的工作原理?不知怎么的,它阻塞了线程1吗

下面是我如何从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
}
以下是我的
螺纹加工方法:

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
}
private void ThreadWork(对象数据)//在Thread2中执行
{
SaveContainer sc=作为SaveContainer的数据;//保存图像
bool[]blankIndex=new bool[sc.imagelist.Count];//用于并行。For循环
对于(int i=0;i//循环标记空白图像
{
boolx=false;//局部变量使循环更有效
x=sc.IsBlankImage((短)i);//检查索引i处的图像是否为空
blankIndex[i]=x;//如果图像为空则设置
}
..//其他图像处理步骤
}
有没有办法“限制”一个并行For循环,这样它就不会使我的处理器达到最大值

是的,您可以添加MaxDegreeOfParallelism=N的选项

或者设置处理优先级

不。它是一个线程池(借用的)线程。不要更改它的属性。实际上它是一组线程池

或者我误解了Parallel.For循环是如何工作的?它是否以某种方式阻塞了Thread1


是的,从外部
并行。For(…)
是一个阻塞调用。因此,在单独的任务或Backgroundworker上运行它,而不是从主线程运行。

一个粗略的方法是在ParallelOptions中使用MaxDegreeOfParallelism标志

var Options = new ParallelOptions();

// Keep one core/CPU free...
Options.MaxDegreeOfParallelism = Environment.ProcessorCount - 1;

Paralle.For(0, sc.imagelist.Count, Options, 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
}

如果没有对整个应用程序的访问,很难准确地知道这里发生了什么,但让我们先来分析一下并行。例如:

private void ThreadWork(object data) // executing in Thread2
{
    // Thread2 running here
    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)

    // Thread2 blocks on this call
    Paralle.For(0, sc.imagelist.Count, i => // loop to mark blank images
    {
        // Thread from the pool is running here (NOT Thread2)!!!

        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
    }
    // Thread2 resumes running here

    .... // other image processing steps
}
private void ThreadWork(对象数据)//在Thread2中执行
{
//线程2正在运行
SaveContainer sc=作为SaveContainer的数据;//保存图像
bool[]blankIndex=new bool[sc.imagelist.Count];//用于并行。For循环
对于(int i=0;i//循环标记空白图像
{
//池中的线程正在此处运行(不是线程2)!!!
boolx=false;//局部变量使循环更有效
x=sc.IsBlankImage((短)i);//检查索引i处的图像是否为空
blankIndex[i]=x;//如果图像为空则设置
}
//Thread2将在此处继续运行
..//其他图像处理步骤
}
因此,更改Thread2的优先级不会产生任何影响,因为它已被阻止。但是,如果Thread1未被阻止,它应该仍然能够运行。Thread1可能不会经常运行,这可能是您的问题

最简单的方法是搞乱线程优先级、计数或添加一些thread.Yield()语句。但是,池中的线程可能已经阻塞了,因为它们正在执行I/O

最有可能的情况是,您需要重构代码,以便图像加载循环使用System.Threading.WaitHandle之类的工具阻止主线程的图像获取,或者将主线程正在做的更多工作转移到图像加载中。经验表明,如果不重构,您最终将得到一个定制的解决方案对于您正在测试的特定机器,在特定的运行条件下,但当负载更改或硬件更改时,您的“调整”将关闭


重新编写代码,以便在并行程序中完成更多的工作。对于工作人员,在主线程有工作时阻止主线程活动,您将获得一个您引以为豪的解决方案。

好的,我已经解决了!我只是在有人无意中发生这种情况时发布此消息

原来,
Parallel.For
线程并没有阻塞Thread1(是的,你没问题)。然而,Thread1中的一个对象试图在循环逐渐消失的同时从
ThreadPool
中获取一个新的
线程,因此出现了“延迟”发生。我正在使用第三方SDK,该SDK允许我与TWAIN界面交互,并且有一个选项
ScanInNewThread=true
,该选项试图在用户每次启动新扫描时获取一个新线程(这是在循环运行时发生的)。我能够更改此选项,以便单个(但仍然是单独的)线程在整个应用程序会话中使用,而不是为每个扫描批抓取一个新线程,而且不会有更明显的延迟

因此,这个故事的寓意是:


现有线程仍应“正常”运行(调用
Parallel.For
循环的线程除外)只要他们在循环进行时不试图从
线程池中抓取更多线程

你确定线程1在等待线程2或其他线程时没有被阻塞吗?查看线程1在等待时正在执行的操作的代码会很有帮助。设置线程2的优先级不会有什么不同,因为并行s r
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());

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