簡體   English   中英

我可以將while(true)循環轉換為EventWaitHandle嗎?

[英]Can I convert while(true) loop to EventWaitHandle?

我試圖通過Parallel.ForEach處理大量文本文件,將處理后的數據添加到BlockingCollection

問題是我希望Task taskWriteMergedFile消耗集合並將它們至少每800000行寫入結果文件中。

我猜我無法在迭代中測試集合的大小,因為它是並行的,所以我創建了Task

在這種情況下,我可以將任務中的while(true)循環轉換為EventWaitHandle嗎?

const int MAX_SIZE = 1000000;
static BlockingCollection<string> mergeData;
mergeData = new BlockingCollection<string>(new ConcurrentBag<string>(), MAX_SIZE);


string[] FilePaths = Directory.GetFiles("somepath");

var taskWriteMergedFile = new Task(() =>
{
    while ( true )
    {
        if ( mergeData.Count  > 800000)
        {
            String.Join(System.Environment.NewLine, mergeData.GetConsumingEnumerable());
            //Write to file
        }
        Thread.Sleep(10000); 
    }
}, TaskCreationOptions.LongRunning);

taskWriteMergedFile.Start();
Parallel.ForEach(FilePaths, FilePath => AddToDataPool(FilePath));
mergeData.CompleteAdding();

您可能不想這樣做。 而是讓您的任務在收到文件時將每一行寫到文件中。 如果要將文件大小限制為80,000行,則在寫入第80,000行之后,關閉當前文件並打開一個新文件。

想一想,您無法使用的東西是因為GetConsumingEnumerable()直到標記為添加完成才被停止。 將會發生的事情是,事情將進入睡眠循環,直到隊列中有80,000個項目,然后它將阻塞在String.Join上,直到主線程調用CompleteAdding為止。 有了足夠的數據,您將耗盡內存。

另外,除非您有充分的理由,否則不應在此處使用ConcurrentBag 只需對BlockingCollection使用默認值,即ConcurrentQueue ConcurrentBag是一個相當特殊目的的數據結構,其性能不如ConcurrentQueue

因此,您的任務變為:

var taskWriteMergedFile = new Task(() =>
{
    int recordCount = 0;
    foreach (var line in mergeData.GetConsumingEnumerable())
    {
        outputFile.WriteLine(line);
        ++recordCount;
        if (recordCount == 80,000)
        {
            // If you want to do something after 80,000 lines, do it here
            // and then reset the record count
            recordCount = 0;
        }
    }
}, TaskCreationOptions.LongRunning);

當然,這假定您已在其他位置打開了輸出文件。 最好在任務開始時打開輸出,並在退出foreach之后將其關閉。

另一方面,您可能不希望生產者循環平行。 你有:

Parallel.ForEach(FilePaths, FilePath => AddToDataPool(FilePath));

我不確定AddToDataPool在做什么,但是如果它正在讀取文件並將數據寫入集合中,則會遇到一些問題。 首先,磁盤驅動器一次只能執行一項操作,因此最終會讀取一個文件的一部分,然后讀取另一個文件的一部分,然后讀取另一個文件的一部分,依此類推。為了讀取下一個文件的每個塊,它必須尋找頭部到正確的位置。 磁盤磁頭搜索的成本非常高--5毫秒或更長。 CPU時間的永恆。 除非您執行的重負荷處理比讀取文件要花費更長的時間,否則最好總是一次處理一個文件。 除非您可以保證輸入文件位於單獨的物理磁盤上。

第二個潛在的問題是,在運行多個線程的情況下,您不能保證將事物寫入集合的順序。 當然,這可能不成問題,但是如果您希望將單個文件中的所有數據歸類到輸出中,則不會發生多個線程,每個線程向集合寫入多行。

只是要記住一點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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