[英]Using thread-local resources with parallel for loops
想象一長串要處理的數據。 處理受CPU限制,可以並行完成。
要處理數據項,需要一個大對象(〜50MB)來保存中間處理結果。 該對象可以在后續任務的處理過程中重復使用。
我想做這樣的事情:
Processor[] processors = GetProcessors(Environment.ProcessorCount);
Parallel.For(
0,
itemCount,
new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
item =>
{
int threadIndex = /* TODO */;
processors[threadIndex].Process(item);
}
);
目標是只擁有我的大對象的Environment.ProcessorCount
實例,並盡可能有效地重用它們。
我怎樣才能做到這一點?
您只需要使用Parallel.For
的重載即可,這需要兩個函數來設置和拆除線程本地對象。
Parallel.For(
0,
itemCount,
() => new Processor(),
new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
(item, loopState, processor) =>
{
processor.Process(item);
// return the processor to be used for another invocation
return processor;
}
processor =>
{
//Do any tear down work you need to do, like dispose the object if it is disposeable
processor.Dispose();
}
);
因為Parallel
類函數不會立即跳轉到使用ParallelOptions.MaxDegreeOfParallelism
線程(它們從一個線程開始,然后逐漸增加到您定義的最大值),所以只有創建了一個線程並且最多具有ParallelOptions.MaxDegreeOfParallelism
它才會創建Processor
一個實例ParallelOptions.MaxDegreeOfParallelism
創建ParallelOptions.MaxDegreeOfParallelism
對象。
我不知道默認調度程序的實現細節,但是它可能會或可能不會停止線程,然后創建新線程,從而導致創建新的Processor
對象。 但是,如果發生這種情況(可能不會,我不知道),您將仍然同時最多只能有ParallelOptions.MaxDegreeOfParallelism
對象。
這是一種可行的方法。 我在寫問題時設計了這個答案,但認為問題很有趣,無論如何都可以發表。 如果有人有更好的解決方案,我想學習。
使用並發集合(例如ConcurrentQueue<Processor>
)在線程之間分配Processor
實例。
Processor[] processors = GetProcessors(Environment.ProcessorCount);
var queue = new ConcurrentQueue<Processor>(processors);
Parallel.For(
0,
itemCount,
new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
item =>
{
// Obtain the processor
Processor processor;
queue.TryDequeue(out processor);
processor.Process(item);
// Store the processor again for another invocation
queue.Enqueue(processor);
}
);
實際的實現應斷言TryDequeue
返回true,並在出現異常的情況下再次使處理器入隊。
只要處理時間遠大於隊列爭用所花費的時間,開銷就應該最小。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.