C# 两线交替
我正在构建的应用程序从某个源读取日志,并将其显示在网格上。日志的大小可以是几MB到几GB。为了防止内存出现任何问题,我使用了一个网格,每次对日志进行500行分页。这就是我希望做的: 我想创建一个线程,该线程将读取日志,并将它们写入一个文件,每次大约500行,然后通知另一个线程日志已被写入。然后,另一个线程将读取文件并在网格上显示行,并向第一个线程发出信号,表示它已完成读取。这种情况一直持续到没有更多的日志要写入文件为止C# 两线交替,c#,multithreading,C#,Multithreading,我正在构建的应用程序从某个源读取日志,并将其显示在网格上。日志的大小可以是几MB到几GB。为了防止内存出现任何问题,我使用了一个网格,每次对日志进行500行分页。这就是我希望做的: 我想创建一个线程,该线程将读取日志,并将它们写入一个文件,每次大约500行,然后通知另一个线程日志已被写入。然后,另一个线程将读取文件并在网格上显示行,并向第一个线程发出信号,表示它已完成读取。这种情况一直持续到没有更多的日志要写入文件为止 可以在这样的线程之间切换吗?是的,当然,这是 您可以在这里使用一些基本的构建
可以在这样的线程之间切换吗?是的,当然,这是 您可以在这里使用一些基本的构建块,如
Thread
和AutoResetEvent
。“producer”从日志中读取行并将它们发布到文件中(也许您可以使用内存缓冲区?),然后向另一个线程发送信号以读取它们:
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
}
这将允许使用者读取文件和生产者读取更多日志并准备下一批之间有一定程度的并行性
当生产者处理完日志后,它可以在文件中放入一条特殊的终止消息,以通知消费者正常退出
这是一种策略,它的级别非常低,而且容易出错。您可以完全跳过共享文件,并使用内存中的缓冲区,缓冲区的形式为
定义一个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
}
BlockingCollection缓冲区=新的BlockingCollection(1);
//生产者任务
而(/*行仍然可用*/)
{
//读500行
ProducerTask p=新的ProducerTask();
buffer.Add(p);//这将阻塞,直到使用者执行上一个任务
}
//消费者任务
而(/*未收到终止*/)
{
ProducerTask p=buffer.Take();//如果没有可用的任务,则阻塞
//把线放在格子里
}
更简单、更优雅。根据都铎非常好的回答,您还可以看到它为实现生产者-消费者模式提供了一套非常干净的构建块。谢谢,这正是我想要的。不过,我不认为我可以使用内存缓冲区,因为一次可以读取的500行是可变的;可以是任何号码。此外,我不想在内存中保存那么多数据,因为应用程序还有其他功能。