一种多线程文件处理方法

时间:2016-01-29 09:43:55

标签: .net multithreading stream thread-safety producer-consumer

我有一个非常大的文件(> 15 GB)(更不用说什么样的文件)。 我必须读取文件,对数据进行一些处理,然后将处理后的数据写入空白文件。 我是以大块的方式做的。每个块都包含某种标题,后跟数据。多个块的最简单文件将包含:

Number of block bytes
Block bytes
Number of block bytes
Block bytes

因此,我创建了一个用于按块读取文件的线程,一些用于处理每个读取块的线程,以及一个用于按块处理数据写入的线程。

我在处理这些线程时遇到了一些问题。

我不知道每个块的处理顺序,但我必须按顺序写入文件块,就像它已被读取一样。

所以,我的问题是我必须使用什么样的方法来管理多线程处理。

我想,如果我使用 producer concumer 模式,可能会更好。在这种情况下,最好用什么数据结构来存储数据?我有一个猜测 - 一个基于数组的堆栈,在开始编写之前我需要排序一次。

但我不确定。所以,请帮助我一个方法。

//sample of my code, but without any logic of threads managing

public class DataBlock
{
    public byte[] Data { get; }
    public long Index { get; }

    public DataBlock(byte[] data, long index)
    {
        this.Data = data;
        this.Index = index;
    }
}


int bufferSize = 1024*64; //65536
long processedBlockCounter = 0L;
MyStack<DataBlock> processedBlockStore = new MyStack<DataBlock>();

using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize))
{
    using (BufferedStream bs = new BufferedStream(fs, bufferSize))
    {
        byte[] buffer = new byte[bufferSize];
        int byteRead;
        while ((byteRead = bs.Read(buffer, 0, bufferSize)) > 0)
        {
            byte[] originalBytes;
            using (MemoryStream mStream = new MemoryStream())
            {
                mStream.Write(buffer, 0, byteRead);
                originalBytes = mStream.ToArray();
            }

            long dataBlockIndex = Interlocked.Increment(ref processedBlockCounter);

            Thread processThread = new Thread(() =>
            {
                byte[] processedBytes = MyProcessor.Process(originalBytes);
                DataBlock processedBlock = new DataBlock(processedBytes, processedBlockCounter);
                lock(processedBlockStore)
                {
                     processedBlockStore.Add(processedBlock);
                }
            });
            processThread.Start();
        }
    }
}

1 个答案:

答案 0 :(得分:2)

您正在为每次迭代创建新线程。这不会扩大规模。我建议你改用ThreadPool。首选方法是使用内部使用ThreadPool的TPL。

由于您需要订购和并行处理而且它们不是齐头并进的,所以如果可以选择,您可以使代码完全同步。

如果您需要并行处理,我建议采用以下Fork-Join策略,因为您的文件大于15 GB并且您的处理也非常耗时。

  • 整理文件
  • 使用每个块启动任务
  • 使每个任务将输出写入名为index的临时文件。 1.txt2.txt
  • 等待所有任务完成
  • 最后阅读这些临时文件并按顺序创建输出文件。
  • 然后当然删除那些临时文件。你完成了。