3 回答

TA贡献1854条经验 获得超8个赞
我将通过首先取消之前的操作来开始写入文件。我还将在延迟任务中包含取消标记。
CancellationTokenSource _cancel_saving;
public void write_to_file()
{
_cancel_saving?.Cancel();
_cancel_saving = new CancellationTokenSource();
Task.Delay(1000, _cancel_saving.Token).ContinueWith((task) =>
{
File.WriteAllBytes("path/to/file.data", _internal_data);
}, _cancel_saving.Token);
}

TA贡献1946条经验 获得超4个赞
你的背景对我来说似乎有点奇怪。您正在写入所有字节,而不是使用流。撇开取消令牌的问题不谈,将写入延迟 1 秒不会减少磁盘的总体负载或总体吞吐量。
这个答案有以下假设:
您正在使用 SSD 并且担心硬件寿命
这是一个低优先级的活动,可以容忍一些数据丢失
这不是日志记录活动(否则附加到文件会更好地使用 a
BufferedStream
)这可能是将序列化的 C# 对象树保存到磁盘以防断电
您不希望对对象树所做的每个更改都会导致写入磁盘。
如果对象树没有变化,您不想每秒都写入磁盘。
如果 N 秒内没有写入,它应该立即写入磁盘
如果最近有写入,它应该等待。
将 WriteAllBytes 步骤作为节流点并不理想。
用法:
rootObject.subObject.value = 9; rootObject.Save(token);
支持代码:
TimeSpan minimumDiskInterval = TimeSpan.FromSeconds(60);
DateTime lastSaveAt = DateTime.MinValue;
bool alreadyQueued = false;
public void Save(CancellationToken token)
{
if (alreadyQueued) //TODO: Interlocked with long instead for atomic memory barrier
return;
alreadyQueued = true; //TODO: Interlocked with long instead for atomic memory barrier
var thisSaveAt = DateTime.UtcNow;
var sinceLastSave = thisSaveAt.Subtract(lastSaveAt);
var difference = TimeSpan.TotalSeconds - sinceLastSave.TotalSeconds;
if (difference < 0)
{
//It has been a while - no need to delay
SaveNow();
}
else
{
//It was done recently
T Task.Delay(TimeSpan.FromSeconds(difference).ContinueWith((task) =>
{
SaveNow();
}, _cancel_saving.Token);
}
}
object fileAccessSync = new object();
public void SaveNow()
{
alreadyQueued = false; //TODO: Interlocked with long instead for atomic memory barrier
byte[] serializedBytes = Serialise(this)
lock (fileAccessSync)
{
File.WriteAllBytes("path/to/file.data", serializedBytes);
}
}

TA贡献1820条经验 获得超10个赞
您应该使用 Microsoft 的 Reactive Framework(又名 Rx)- NuGetSystem.Reactive并添加using System.Reactive.Linq;- 然后您可以这样做:
public class ThrottleTest
{
private byte[] _internal_data = new byte[256];
private Subject<Unit> _write_to_file = new Subject<Unit>();
public ThrottleTest()
{
_write_to_file
.Throttle(TimeSpan.FromSeconds(1.0))
.Subscribe(_ => File.WriteAllBytes("path/to/file.data", _internal_data));
}
public void write_to_file()
{
_write_to_file.OnNext(Unit.Default);
}
public void operation_that_update_internal_data()
{
/*
* operate on _internal_data
*/
write_to_file();
}
public void another_operation_that_update_internal_data()
{
/*
* operate on _internal_data
*/
write_to_file();
}
}
- 3 回答
- 0 关注
- 99 浏览
添加回答
举报