1

我正在构建的应用程序从某个源读取日志并将其显示在网格上。日志的大小可以是几 MB 到几 GB。为防止内存出现任何问题,我使用网格并一次通过日志分页 500 行。这是我希望做的:

我想创建一个线程,它将读取日志并将它们每次写入大约 500 行的文件,然后通知另一个线程已写入日志。然后另一个线程将读取文件并在网格上显示行,并向第一个线程发出它已完成读取的信号。这种情况一直持续到没有更多日志写入文件。

是否可以像这样在线程之间切换?

4

2 回答 2

2

是的,当然,它是生产者-消费者模型的变体。

您可以在这里使用一些基本的构建块,例如ThreadAutoResetEvent。“生产者”从日志中读取行并将它们发布到文件中(也许您可以使用内存缓冲区来代替?)然后向另一个线程发出信号以读取它们:

AutoResetEvent consumerEvent = new AutoResetEvent(false);
AutoResetEvent producerEvent = new AutoResetEvent(false);

// producer code
while(/* lines still available */)
{
    // read 500 lines
    // write to shared file
    consumerEvent.Set(); // signal consumer thread
    producerEvent.WaitOne(); // wait to be signaled to continue
}

和消费者代码:

while(/* termination not received */)
{
    consumerEvent.WaitOne(); // wait for the producer to finish     
    // read lines from file and put them in the grid
    producerEvent.Set(); // allow producer to read more logs
}

这将允许消费者读取文件和生产者读取更多日志并准备下一批之间存在一定程度的并行性。

当生产者完成日志后,它可以在文件中放置一条特殊的终止消息,以通知消费者正常退出。

这是一种策略,它非常低级且容易出错。您可以完全跳过共享文件并使用BlockingCollection形式的内存缓冲区。

定义一个ProducerTask类来保存一些文本行:

class ProducerTask 
{
    public String[] Lines { get; set; }
}

此任务一次将保存 500 行。

然后使用TaskBlockingCollection(.NET 4.0+)如下:

BlockingCollection<ProducerTask> buffer = new BlockingCollection<ProducerTask>(1);

// producer task
while(/* lines still available */)
{
    // read 500 lines
    ProducerTask p = new ProducerTask();
    buffer.Add(p); // this will block until the consumer takes the previous task
}

// consumer task
while(/* termination not received */)
{
    ProducerTask p = buffer.Take(); // blocks if no task is available
    // put the lines in the grid
}

更加简单和优雅。

于 2012-06-01T11:58:05.533 回答
0

在 Tudor 的非常好的回答之后,您还可以查看TPL Dataflow,它提供了一组非常干净的构建块来实现生产者-消费者模式。

于 2012-06-01T12:54:08.547 回答