如何确保在当前文件上的所有 WriteAsync() 完成后处理 FileStream?
How can one ensure that FileStream is disposed of after all WriteAsync() on the current file are complete?
我有以下事件委托,它基本上接受字节数组,并将其附加到文件流。一旦写入 1,000 次,由局部变量 counter
跟踪,我想关闭当前文件流并打开一个新文件流。
我通读了 FileStream 的文档,它建议使用 FileStream.WriteAsync()
以获得更好的性能。
public void WriteData(byte[] data)
{
counter++;
if (counter == 1000)
{
counter = 0;
// Close the current filestream and open a new one.
filestream.Dispose();
filestream = new FileStream(this.outputPath, FileMode.Create,
FileAccess.Write, FileShare.None, 4096, true);
}
filestream.WriteAsync(data, 0, data.Length);
}
然而,在上面的函数中,我的假设是可能是在我调用filestream.Dispose()
之前所有WriteAsync()
调用都没有完成的情况。有没有办法确保在我的所有 WriteAsync()
调用完成后我只 Dispose()
?请注意,此事件委托每秒按顺序调用 1,000 - 2,000 次,WriteAsync 每次调用将 240 KB 复制到 SSD。
我能想到的一个解决方案不是立即处理每个 Filestream
,我可以将它存储在一个 Filestream
的数组中,然后在我完成处理后处理它们整个数据写入过程,不再触发任何事件。那行得通吗?即便如此,在所有 WriteAsync()
调用完成之前,我如何有效地 "wait"?
虽然不是对确切问题的回答,但根据后续评论,我建议您执行以下操作:
- 在触发事件的任何地方创建一个
ConcurrentQueue
- 在每个事件中,添加到该队列
- 创建一个单独的线程来为队列服务,使事件出队并将它们写入磁盘。然后,您可以准确控制打开、写入、重命名等操作的频率,并且文件上没有线程并发问题需要处理activity。
- 根据您的要求,在您的编写器线程中,您可以每隔一秒左右轮询一次队列,或者您可以采用更复杂的方法使用
WaitHandle
s 在数据准备好写入时发出信号,当队列为空,当其中有 N 个项目时,等等。由于您如此频繁地积累数据,也许轮询很好,因为您几乎总能找到要写入的数据。
- 您显然需要彻底关闭应用程序 - 例如停止从事件中写入,单到写入线程停止,让它将最后的项目刷新到磁盘,等待它停止。
工作量更大,但您得到:
- 保证订单
- 几乎没有时间花在事件处理程序上
- 没有并发问题(管理设置和拆卸除外)
- 写作延迟 - 例如由于 OS、磁盘、网络 - 不要阻止主应用程序
- 如果您断电或应用程序中止,则存在丢失事件数据的风险(您将使用任何不等待在每个事件后写入数据的解决方案)
可能有现成的解决方案(想到使用缓冲的 log4net Appender);这是如果你想自己动手。
您可以使用 'standard' 线程(即 Thread
)来执行此操作,或者您可以将您的写作线程创建为 Task
。
我有以下事件委托,它基本上接受字节数组,并将其附加到文件流。一旦写入 1,000 次,由局部变量 counter
跟踪,我想关闭当前文件流并打开一个新文件流。
我通读了 FileStream 的文档,它建议使用 FileStream.WriteAsync()
以获得更好的性能。
public void WriteData(byte[] data)
{
counter++;
if (counter == 1000)
{
counter = 0;
// Close the current filestream and open a new one.
filestream.Dispose();
filestream = new FileStream(this.outputPath, FileMode.Create,
FileAccess.Write, FileShare.None, 4096, true);
}
filestream.WriteAsync(data, 0, data.Length);
}
然而,在上面的函数中,我的假设是可能是在我调用filestream.Dispose()
之前所有WriteAsync()
调用都没有完成的情况。有没有办法确保在我的所有 WriteAsync()
调用完成后我只 Dispose()
?请注意,此事件委托每秒按顺序调用 1,000 - 2,000 次,WriteAsync 每次调用将 240 KB 复制到 SSD。
我能想到的一个解决方案不是立即处理每个 Filestream
,我可以将它存储在一个 Filestream
的数组中,然后在我完成处理后处理它们整个数据写入过程,不再触发任何事件。那行得通吗?即便如此,在所有 WriteAsync()
调用完成之前,我如何有效地 "wait"?
虽然不是对确切问题的回答,但根据后续评论,我建议您执行以下操作:
- 在触发事件的任何地方创建一个
ConcurrentQueue
- 在每个事件中,添加到该队列
- 创建一个单独的线程来为队列服务,使事件出队并将它们写入磁盘。然后,您可以准确控制打开、写入、重命名等操作的频率,并且文件上没有线程并发问题需要处理activity。
- 根据您的要求,在您的编写器线程中,您可以每隔一秒左右轮询一次队列,或者您可以采用更复杂的方法使用
WaitHandle
s 在数据准备好写入时发出信号,当队列为空,当其中有 N 个项目时,等等。由于您如此频繁地积累数据,也许轮询很好,因为您几乎总能找到要写入的数据。 - 您显然需要彻底关闭应用程序 - 例如停止从事件中写入,单到写入线程停止,让它将最后的项目刷新到磁盘,等待它停止。
工作量更大,但您得到:
- 保证订单
- 几乎没有时间花在事件处理程序上
- 没有并发问题(管理设置和拆卸除外)
- 写作延迟 - 例如由于 OS、磁盘、网络 - 不要阻止主应用程序
- 如果您断电或应用程序中止,则存在丢失事件数据的风险(您将使用任何不等待在每个事件后写入数据的解决方案)
可能有现成的解决方案(想到使用缓冲的 log4net Appender);这是如果你想自己动手。
您可以使用 'standard' 线程(即 Thread
)来执行此操作,或者您可以将您的写作线程创建为 Task
。