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)
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)
好吧,我明白了!我只是发布此内容以防万一有人无意中发生这种情况......
事实证明,该Parallel.For线程并未阻塞 Thread1(是的,你没问题)。然而,当循环正在运行时,Thread1 中的一个对象试图Thread从Thread1 中获取一个新对象ThreadPool,因此发生了“延迟”。我使用的是第 3 方 SDK,它允许我与 TWAIN 界面进行交互,并且有一个选项ScanInNewThread = true可以在每次用户开始新扫描时尝试获取新线程(这是在循环运行时发生的)。我能够更改此设置,以便在整个应用程序会话中使用单个(但仍然是单独的)线程,而不是为每个扫描批次抓取一个新线程,然后砰的一声,不再有明显的延迟。
SO - 这个故事的寓意:
现有线程应该仍然“正常”运行(调用循环的线程除外Parallel.For),只要它们在ThreadPool循环进行时不尝试从循环中获取更多线程即可。