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