快速将数据保存在磁盘上;如何?使用辅助内存缓冲区?
Quick save data on disk; how to? Use a auxiliary memory buffer?
我用 C# 编写了一个应用程序,用于从连接到以太网网络的某些设备读取一些数据(以轮询模式)。许多并行任务被启动,每个配置的设备一个;在所有任务结束时,读取的数据存储在 stringbuilder 中,然后以追加模式保存到文件中。如果将轮询时间设置得较高(例如大于 5/6 秒),则一切正常。对于较短的时间,磁盘 IO 活动可能无法保存 strinbuilder 中包含的数据量(当第二个保存数据的过程需要开始时,第一个保存过程尚未结束,依此类推......)。我怎么解决这个问题?我想创建一个类似于 "memory buffer" 的控件,将填充有设备数据的 stringbuilder (sbData) 复制到用于在固定时间(例如每 30 秒)保存数据的支持 stringbuilder (sbAux)。成功保存数据后,在 30 秒结束时再次复制新数据 (sbAux = sbData)。还有其他方法吗?你能给我一些建议吗?
非常感谢大家的建议。
好的 - 如果读取数据所花费的时间在 50 到 x,000 毫秒之间,您将不得不忘记将所有数据保持在整洁的行中。相反,我会建议两个阶段。
您的第一个阶段是一个缓冲区,它确实 很快,并且只是尽快接受数据。它执行最少的检查——例如,只是为了确保数据的格式正确。您必须决定 "minimal checking" 的含义,但它只会抛出明显错误的数据(可能只是忽略它并记录警告,也许)。其他任何东西都会被添加到队列中。队列旨在将数据添加到队列的后面并从前面读取。您必须决定它最多可以容纳多少数据,只有实验才能告诉您。
您可以在以下位置找到有关如何使用队列的信息:
- https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.queue-1.enqueue?view=netframework-4.7.2
- http://www.tutorialsteacher.com/csharp/csharp-queue
您必须继承 Queue 以适合您自己的数据并使其成为线程安全的,因为将有超过 1 个线程写入和读取它。
您的工作线程从设备读取并在可用时提交读数。他们不会尝试对数据进行排序或担心丢失数据,他们只是:
- 读取数据
- 将其放入队列
- 忘记数据
- 睡觉或根据需要继续阅读下一篇文章
记住:从设备获取数据到队列是时间紧迫的,因此在此操作的这一部分没有 "thinking"。
我会考虑对您的数据进行批处理 - 即您添加单个项目,这些项目被添加到一个块中,比方说 32 个读数。整个块被添加到队列中。读取数据时,它不会读取一次数据,而是读取一批 x 项(在本例中为 32 项)。这意味着队列处理的写入比读取多得多。
你的第二个阶段是所有大脑所在的地方。该缓冲区(或多个缓冲区,具体取决于您要写入的文件数量)从队列中读取并对其进行排序。您必须决定如何订购它的规则。但是这个操作不是时间紧迫的。它从队列中读取数据,查看数据用于什么设备,时间戳是什么,并计算出是否有任何由于超时而丢失的读数,并构建保存到磁盘的数据。如果您为每个设备创建 1 个文件,那么这就是数据分离的地方。
将这两个操作分开的意义在于,您工作的时间关键部分不会被相对较慢的排序和写入磁盘部分所拖延。不要只是继续向您的模型中添加线程 - 反其道而行之,尽量减少线程数。第二阶段应该循环很多,比第一阶段慢得多。
这是它如何工作的粗略概念:
正如 Doc 在回到未来中所说的那样,"You'll have to forgive the crudity of the model."
我知道这只是一般指导,但我希望它能帮助您并朝着正确的方向前进。
祝你好运,亲切问候!
亚当。
我用 C# 编写了一个应用程序,用于从连接到以太网网络的某些设备读取一些数据(以轮询模式)。许多并行任务被启动,每个配置的设备一个;在所有任务结束时,读取的数据存储在 stringbuilder 中,然后以追加模式保存到文件中。如果将轮询时间设置得较高(例如大于 5/6 秒),则一切正常。对于较短的时间,磁盘 IO 活动可能无法保存 strinbuilder 中包含的数据量(当第二个保存数据的过程需要开始时,第一个保存过程尚未结束,依此类推......)。我怎么解决这个问题?我想创建一个类似于 "memory buffer" 的控件,将填充有设备数据的 stringbuilder (sbData) 复制到用于在固定时间(例如每 30 秒)保存数据的支持 stringbuilder (sbAux)。成功保存数据后,在 30 秒结束时再次复制新数据 (sbAux = sbData)。还有其他方法吗?你能给我一些建议吗?
非常感谢大家的建议。
好的 - 如果读取数据所花费的时间在 50 到 x,000 毫秒之间,您将不得不忘记将所有数据保持在整洁的行中。相反,我会建议两个阶段。
您的第一个阶段是一个缓冲区,它确实 很快,并且只是尽快接受数据。它执行最少的检查——例如,只是为了确保数据的格式正确。您必须决定 "minimal checking" 的含义,但它只会抛出明显错误的数据(可能只是忽略它并记录警告,也许)。其他任何东西都会被添加到队列中。队列旨在将数据添加到队列的后面并从前面读取。您必须决定它最多可以容纳多少数据,只有实验才能告诉您。
您可以在以下位置找到有关如何使用队列的信息:
- https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.queue-1.enqueue?view=netframework-4.7.2
- http://www.tutorialsteacher.com/csharp/csharp-queue
您必须继承 Queue 以适合您自己的数据并使其成为线程安全的,因为将有超过 1 个线程写入和读取它。
您的工作线程从设备读取并在可用时提交读数。他们不会尝试对数据进行排序或担心丢失数据,他们只是:
- 读取数据
- 将其放入队列
- 忘记数据
- 睡觉或根据需要继续阅读下一篇文章
记住:从设备获取数据到队列是时间紧迫的,因此在此操作的这一部分没有 "thinking"。
我会考虑对您的数据进行批处理 - 即您添加单个项目,这些项目被添加到一个块中,比方说 32 个读数。整个块被添加到队列中。读取数据时,它不会读取一次数据,而是读取一批 x 项(在本例中为 32 项)。这意味着队列处理的写入比读取多得多。
你的第二个阶段是所有大脑所在的地方。该缓冲区(或多个缓冲区,具体取决于您要写入的文件数量)从队列中读取并对其进行排序。您必须决定如何订购它的规则。但是这个操作不是时间紧迫的。它从队列中读取数据,查看数据用于什么设备,时间戳是什么,并计算出是否有任何由于超时而丢失的读数,并构建保存到磁盘的数据。如果您为每个设备创建 1 个文件,那么这就是数据分离的地方。
将这两个操作分开的意义在于,您工作的时间关键部分不会被相对较慢的排序和写入磁盘部分所拖延。不要只是继续向您的模型中添加线程 - 反其道而行之,尽量减少线程数。第二阶段应该循环很多,比第一阶段慢得多。
这是它如何工作的粗略概念:
正如 Doc 在回到未来中所说的那样,"You'll have to forgive the crudity of the model." 我知道这只是一般指导,但我希望它能帮助您并朝着正确的方向前进。
祝你好运,亲切问候!
亚当。