节流文件操作

时间:2019-03-30 20:54:24

标签: c# task throttling

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

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[]>,而其中任何byte[]都可以独立进行修改?

3 个答案:

答案 0 :(得分:0)

我将通过先取消上一个操作来开始写入文件。 我还将在“延迟”任务中包含取消令牌。

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);
}

答案 1 :(得分:0)

您应该使用Microsoft的Reactive Framework(又名Rx)-NuGet System.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();
    }
}

答案 2 :(得分:0)

您的情况对我来说有点奇怪。您正在写入所有字节,而不使用流。撇开取消令牌的问题,将写入延迟1秒不会减少磁盘的总体负载或总体吞吐量。

此答案具有以下假设:

  • 您正在使用SSD,并且担心硬件寿命
  • 这是低优先级的活动,可以容忍一些数据丢失
  • 这不是日志记录活动(否则,将文件追加到props.route.params.fullName下会更好)
  • 如果断电,这很可能会将序列化的C#对象树保存到磁盘上
  • 您不希望对对象树进行的所有更改都导致对磁盘的写操作。
  • 如果对象树没有变化,您不想每秒写入磁盘。
  • 如果N秒钟没有写入,它应该立即写入磁盘
  • 如果最近有写操作,应该等待。

将WriteAllBytes步骤作为调节点是不理想的。

用法:

BufferedStream

支持代码:

rootObject.subObject.value = 9;
rootObject.Save(token);