我正在构建的应用程序从某些源读取日志并将其显示在网格上。日志大小可以是几MB到几GB。为了防止内存出现任何问题,我一次使用网格并在日志中划分500行。这是我希望做的:
我想创建一个线程,它将读取日志并将它们写入每次大约500行的文件,然后发信号通知另一个已写入日志的线程。然后另一个线程将读取文件并在网格上显示行,并向第一个线程发出已完成读取的信号。这种情况一直持续到没有更多的日志写入文件。
是否可以在这样的线程之间切换?
答案 0 :(得分:2)
是的,当然,它是producer-consumer model的变体。
您可以在此处使用一些基本构建基块,例如Thread
和AutoResetEvent
。 “生产者”从日志中读取行并将它们发布到文件中(也许您可以使用内存缓冲区?)然后通知另一个线程读取它们:
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行。
然后使用Task
和BlockingCollection
(.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
}
更加简单和优雅。
答案 1 :(得分:0)
继Tudor的非常好的答案之后,您还可以查看TPL Dataflow,它提供了一套非常简洁的构建块来实现生产者 - 消费者模式。