簡體   English   中英

將線程本地資源與並行for循環一起使用

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM