0

I am working with a dnp3 nuget package and I want to implement it in a WPF, and I achieve it by referring to this example https://github.com/stepfunc/dnp3/blob/master/ffi/bindings/dotnet/examples/master/Program.cs I managed to implement it by an MVVM method where it dynamically shows the messages it receives (in the gif it shows an error because it did not create another program that will connect but the important thing is that it is being updated).

Example

but I created another much simpler project to do the demonstration here on github , in my project create a class called protocol and paste all the master example eliminating the main function and changing the private functions for public functions, then inside my MainWindow.xaml.cs start the code

    {
        public MainWindow()
        {
            InitializeComponent();
            // ANCHOR: logging_init
            // Initialize logging with the default configuration
            // This may only be called once during program initialization
            Logging.Configure(
                new LoggingConfig(),
                new Protocolo.ConsoleLogger()
            );
            // ANCHOR_END: logging_init

            // ANCHOR: runtime_init
            var runtime = new Runtime(new RuntimeConfig { NumCoreThreads = 4 });
            // ANCHOR_END: runtime_init

            // ANCHOR: create_master_channel
            var channel = MasterChannel.CreateTcpChannel(
                runtime,
                LinkErrorMode.Close,
               Protocolo. GetMasterChannelConfig(),
                new EndpointList("127.0.0.1:20000"),
                new ConnectStrategy(),
                new Protocolo.TestListener()
            );
            // ANCHOR_END: create_master_channel

                Task.Run(() => 
                {
                    try
                    {
                        Protocolo.RunChannel(channel).GetAwaiter().GetResult();
                    }
                    finally
                    {
                        // ANCHOR: runtime_shutdown
                        runtime.Shutdown();
                        // ANCHOR_END: runtime_shutdown
                    }
            }
            );

        }
    } 

I did performance profiles and RunChannel is what they demand a lot from the CPU

        public static async Task RunChannel(MasterChannel channel)
        {
            // ANCHOR: association_create
            var association = channel.AddAssociation(
                1024,
                GetAssociationConfig(),
                new TestReadHandler(),
                new TestAssocationHandler()
            );
            // ANCHOR_END: association_create

            // ANCHOR: add_poll
            var poll = channel.AddPoll(association, Request.ClassRequest(false, true, true, true), TimeSpan.FromSeconds(5));
            // ANCHOR_END: add_poll

            // start communications
            channel.Enable();

            while (true)
            {
              //Here there was a switch that read the commands that were entered into the console but it is unnecessary, with the empty while it continues to update

            }
        }

I don't know why but without the While the received messages are not updated, (these messages arrive in the Logger) I have to keep this function always alive but I don't know how to do it without consuming so much CPU

to see the messages in the output you have to change Console.WriteLine to Debug.WriteLine

   class ConsoleLogger : ILogger
    {
        public void OnMessage(LogLevel level, string message)
        {
            Console.Write($"{message}");
            //this is inside the master example in the github link
        }
    }
  • 2
    `while (true)` is not a good idea, but if you want to use it , put `Sleep(5)` inside it. – Maria Oct 04 '21 at 19:03
  • @Maria I don't want to use it :(, but I don't know how to replace it, this function has to be kept alive for it to update, i wil try it anyway – Ivan Raul Sanchez Diaz Oct 04 '21 at 19:05
  • 2
    Your `async` method is missing an `await` call. If you `await` your long-running process, WPF is free to use that thread for other things while you're `await`ing the answer. No need for a `while(true)`. – Robert Harvey Oct 04 '21 at 19:05

1 Answers1

2

As commented before (answering about "performance issue"):

  1. Your empty while loop running without any pause or job. You need to fill loop with some job or simple pause (Thread.Sleep(10)/await Task.Delay(10)).
  2. Your RunChannel method have no any await, so you should get CS1998 warning "This async method lacks 'await'" and, obviously, put it into your while loop.

On DNP3 Github example, there is await GetInputAsync() inside while loop, which waits for user input with Console.ReadLine() and returns inputed string into switch statement.

So:

public MainWindow()
{
    // InitializeComponent() and other stuff...

    Task.Run(async () => // Make it async
    {
        try
        {
            // You really didn't want GetAwaiter().GetResult().
            await Protocolo.RunChannel(channel);
        }
        finally
        {
            runtime.Shutdown();
        }
    });
}

public class Protocolo 
{
    public static async Task RunChannel(MasterChannel channel)
    {
        // Associations and polls stuff...

        while (true)
        {
            await Task.Delay(10); // Set some delay or...

            await SomeJob(); // ...or do some job or ...

            switch (await GetInputAsync())  // ...or take github's example
            {
                case "x":
                    return;                    
                default:
                    Console.WriteLine("Unknown command");
                    break;
            }
        }
    }

    public static Task SomeJob()
    {
        return Task.Run(() => 
        {
            for (int i = 0; i < 5; i++)
            {
                 Thread.Sleep(200); // 200 x 5 = Total task for 1 second
            }
        });
    }

    public static Task<string> GetInputAsync()
    {
        return Task.Run(() => Console.ReadLine());
    }       
}
Auditive
  • 1,607
  • 1
  • 7
  • 13
  • I deleted everything that was inside the switch for two reasons, first because I was consuming a lot of CPU and in WPF I am no longer using the console, the second is because I found another way to pass the commands, but now that I read your answer I realize It was consuming a lot of memory because it had no pause, I implemented the task delay inside the while and async in the main window and it improved a lot! Thank you very much friend, you saved my life. – Ivan Raul Sanchez Diaz Oct 04 '21 at 20:55