0

当 EasyModbus TCP 计时器内的方法数量增加时,WinForms 应用程序会变慢。应该怎么做才能提高应用程序的速度?

我正在使用 Modbus TCP/IP 从 WinForms 应用程序连接从设备。EasyModbus TCP/IP 库用于建立 WinForms 应用程序和从设备之间的通信,数据(浮点数)应该不断地从客户端读取和写入,因此方法被写入一个用于 Modbus 通信的计时器中。当方法的数量增加时,整个应用程序就会变慢。

using EasyModbus;

ModbusClient modbusClient;

tmr_Modbus_Com.Enabled = false;
timer1.Enabled = false;
private void tmr_Modbus_Com_Tick(object sender, EventArgs e)
    {
        tmr_Modbus_Com.Enabled = false;

        modbusClient.WriteMultipleRegisters(2, ModbusClient.ConvertFloatToRegisters((float)variable, ModbusClient.RegisterOrder.HighLow)); //writing float data in "variable" to client register 40001 and 40002

        textbox1.Text = ModbusClient.ConvertRegistersToFloat(modbusClient.ReadHoldingRegisters(394, 2), ModbusClient.RegisterOrder.HighLow).ToString(); //reading data from two registers 393 and 394 and displays on a textbox, "textbox1"

        tmr_Modbus_Com.Enabled = true

    }

上面的代码返回预期的结果,它从 WinForms 写入浮点数据到寄存器号 40001,它从客户端 ModBus 寄存器 40395 读取数据并显示在文本框中。

当读取和写入数据的方法数量增加时,整个应用程序会变慢,因为需要同时访问来自多个寄存器的数据。

谁能帮我解决这个问题,如何一次访问多个寄存器而不减慢整个应用程序的速度?

4

1 回答 1

2

您的应用程序没有响应,因为您正在事件调度线程上执行 I/O。这会阻止它执行其他任务,例如绘制 UI、对鼠标事件做出反应......

要在线程池上执行 I/O,您可以像这样使用 async/await(未经测试!

// 1. Run the Write - Part on a Threadpool Thread ...
private Task WriteRegAsync( float variable , ModbusClient client )
{
    return Task.Run(() => {
        client.WriteMultipleRegisters(
                     2,  
                     ModbusClient.ConvertFloatToRegisters( variable,
                                                           ModbusClient.RegisterOrder.HighLow)
         );
    });
}

// 2. Run the Read-Part on a Threadpool Thread
private Task<string> ReadRegAsync( int address, ModbusClient client )
{
    return Task.Run( () => {
        return ModbusClient.ConvertRegistersToFloat( 
                                  client.ReadHoldingRegisters(address, 2), 
                                  ModbusClient.RegisterOrder.HighLow)
                           .ToString();
    });
}

// "async" makes "await" available for use. Since this is an EventHandler, "async void" is ok. (Usually, you make that "async Task") 
private async void tmr_Modbus_Com_Tick(object sender, EventArgs e)
{
    tmr_Modbus_Com.Enabled = false;

    // Write _asynchronously_, your app will stay responsive.
    await WriteRegAsync( (float)variable, modbusClient );
    // then read asynchronously. Again, App will stay responsive.
    textbox1.Text = await ReadRegAsync(384, modbusClient);

    tmr_Modbus_Com.Enabled = true
}

请注意,这不是生产就绪代码!对事件处理程序的相邻调用可能会相互“超越”。您可能想要添加一些错误处理、日志记录...

还有一点:如果ModbusClient已经提供了异步方法,那么就使用它们。上面的例子或多或少只是使用一个额外的线程来同时处理你的 UI 内容的 I/O。

于 2019-10-14T12:11:05.767 回答