限制文件操作

我有一个字节数组,我想保存在一个文件中。但是,我不想每次更新都写入文件,因为它可以非常频繁地更新。目前我正计划使用类似于以下的方法;


class ThrottleTest

{

    private byte[] _internal_data = new byte[256];


    CancellationTokenSource _cancel_saving = new CancellationTokenSource();


    public void write_to_file()

    {

        Task.Delay(1000).ContinueWith((task) =>

        {

            File.WriteAllBytes("path/to/file.data", _internal_data);

        }, _cancel_saving.Token);

    }


    public void operation_that_update_internal_data()

    {

        // cancel writing previous update

        _cancel_saving.Cancel();

        /*

         *  operate on _internal_data

         */


        write_to_file();

    }


    public void another_operation_that_update_internal_data()

    {

        // cancel writing previous update

        _cancel_saving.Cancel();

        /*

         *  operate on _internal_data

         */


        write_to_file();

    }

}

我认为这种方法行不通,因为当我取消令牌一次时,它将永远取消,因此它永远不会写入文件。


首先,我想知道我是否在正确的轨道上,上面的代码是否可以工作。如果没有,实现此行为的最佳方法是什么。此外,是否有一种实用的方法可以将其推广到Dictionary<string,byte[]>anybyte[]可以独立修改的地方?


Smart猫小萌
浏览 100回答 3
3回答

哔哔one

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

绝地无双

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

拉莫斯之舞

您应该使用 Microsoft 的 Reactive Framework(又名 Rx)- NuGetSystem.Reactive并添加using System.Reactive.Linq;- 然后您可以这样做:public class ThrottleTest{&nbsp; &nbsp; private byte[] _internal_data = new byte[256];&nbsp; &nbsp; private Subject<Unit> _write_to_file = new Subject<Unit>();&nbsp; &nbsp; public ThrottleTest()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; _write_to_file&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .Throttle(TimeSpan.FromSeconds(1.0))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .Subscribe(_ => File.WriteAllBytes("path/to/file.data", _internal_data));&nbsp; &nbsp; }&nbsp; &nbsp; public void write_to_file()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; _write_to_file.OnNext(Unit.Default);&nbsp; &nbsp; }&nbsp; &nbsp; public void operation_that_update_internal_data()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; /*&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;*&nbsp; operate on _internal_data&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;*/&nbsp; &nbsp; &nbsp; &nbsp; write_to_file();&nbsp; &nbsp; }&nbsp; &nbsp; public void another_operation_that_update_internal_data()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; /*&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;*&nbsp; operate on _internal_data&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;*/&nbsp; &nbsp; &nbsp; &nbsp; write_to_file();&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP