1

I need to save state of a complex C# object every 5 mins.

I am using this basic approach below. I found a "fast" object copy from link lower down.

If I comment out the "Task" part of WriteToBinaryFileTask, leaving only the Copy, then process takes 160ms. This is too long for my needs. The object is likely to update every few milliseconds. I need to take a copy as I cannot lock the actual object whilst writing to disk as that takes 1500ms.

What alternatives might I try to take a snap of the state of my object. I really need to get time down to 10ms.

        private void SaveState()
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();

            UtilsBinarySerialization.WriteToBinaryFileTask<int>(StatePath("PreviousSignalMainLogic"), PreviousSignalMainLogic);

            sw.Stop();
            Console.WriteLine("Secs: " + sw.ElapsedMilliseconds);
        }

    public static void WriteToBinaryFileTask<T>(string filePath, T objectToWrite, bool append = false)
    {
        T objectCopy = ObjectExtensions.Copy(objectToWrite);

        Task taskA = new Task(() =>
        {
            using (Stream stream = File.Open(filePath, append ? FileMode.Append : FileMode.Create))
            {
                var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                binaryFormatter.Serialize(stream, objectCopy);
            }
        }
        );
        taskA.Start();

    }

https://github.com/Burtsev-Alexey/net-object-deep-copy/blob/master/ObjectExtensions.cs

ManInMoon
  • 6,795
  • 15
  • 70
  • 133
  • Serialize/deserialize is a general approach for deep cloning. Use favorite serializer which doesn't require file. `BinaryFormatter` should work with `MemoryStream`, I doubt it's the [fastest one](https://stackoverflow.com/q/4143421/1997232). – Sinatr Jun 03 '19 at 11:15
  • You speak of saving the state "every 5 minutes", so I assume that is how often you need to save to disk, while the actual object changes much faster. The main operation consuming time in your current code is probably saving to disk, so you could try to use a `MemoryStream` instead of a file stream and keep the data in memory. Then have a timer that, every 5 minutes, writes the data in memory back to disk. – Master_T Jun 03 '19 at 11:18
  • 1
    As a general rule, `BinaryFormatter` should not be used for persistence - it is very unreliable between versions etc. In addition to being unreliable, it also isn't known for its speed... – Marc Gravell Jun 03 '19 at 11:19
  • How long does `ObjectExtensions.Copy(objectToWrite)` take? – Patrick Hofman Jun 03 '19 at 11:24
  • Is that for generic or you have a specific object? I mean writing a specific Clone method in the object should be quit fast. But that means it's not a dynamic. And the manual cloning can be nightmare to maintain. – Drag and Drop Jun 03 '19 at 11:27
  • @PatrickHofman The copy itself takes 160ms. The write to disk is not relavent as it gets done a separate thread. – ManInMoon Jun 03 '19 at 11:29
  • It would be very useful if we have a little more information on the complexity of the "complex object". How much data is in it? – Patrick Hofman Jun 03 '19 at 11:30
  • @PatrickHofman. I understand your request, but in reality I need to apply this to lots of different but equally complex objects. Each object class contains 1 or 2 queues of double or datetime elements and the queues can be up to 5K elements in length – ManInMoon Jun 03 '19 at 11:33
  • @ManInMoon I hate to say it, but that `ObjectExtensions.Copy` code looks pretty slow... it is using raw (non-optimized) reflection iteratively. Seriously, you should try using a good serializer (like, *ahem* protobuf-net) and write to a `MemoryStream`. It'll probably be **faster** than trying to deep-clone the object, and then all you need to do is write the `MemoryStream`'s buffer to disk, which you can do separately. (the "*ahem*" there is because I'm massively biased). If you had real code for your `T objectToWrite`, I'd probably be able to help more. – Marc Gravell Jun 03 '19 at 11:39
  • I wouldn't advise you to write it to a file using a task. At least, you'll have to know if the previous `WriteToBinaryFileTask` is finished. You'd probably better of by writing it to a queue. You could use a task but it should be aware of other actions that writes to files. – Jeroen van Langen Jun 03 '19 at 12:20
  • @JeroenvanLangen Why do I need to know if it has finished? I only do this evey 5 minutes and write takes 1.5 seconds. – ManInMoon Jun 03 '19 at 12:44
  • @MarcGravell Yes I see. However, the reason I use BinaryFormatter is that it doesn't require me to make much in the way of annotations to the classes. I generally use ZeroFormatter when I want to serialise something specific in a speedy manner. Here I need to be fairly general. – ManInMoon Jun 03 '19 at 13:44
  • @ManInMoon I didn't realize you're only calling it ones. But you'll probably want to call it multiple times in the future, – Jeroen van Langen Jun 03 '19 at 18:05

0 Answers0