GhostFlying
GhostFlying

Reputation: 819

Serial Port Performance

I want to communicate with a DSP using RS232, so I use System.IO.SerialPort to achieve this. Everything goes well except the reading performance.

Every 200ms, the port can received a package of 144 bytes. But in the tests, the applications almost skip every other package. I try to print the system time in the console. It amaze me that the code below (when length = 140) take me over 200ms. It let the application can not handle the data in time.

Does anything wrong I do?

Port Property:

BaudRate = 9600

Parity = None

StopBits = One

    private byte[] ReadBytesInSpicifiedLength(int length)
    {
        byte[] des = new byte[length];

        for (int i = 0; i < length; i++)
        {
            des[i] = (byte)serialPort.ReadByte();
        }

        return des;
    }

Upvotes: 1

Views: 2571

Answers (1)

Ben Voigt
Ben Voigt

Reputation: 283614

You're doing a lot of individual I/O calls, which means a lot of kernel transitions. Those are expensive. Not being able to reach 720 bytes per second is surprising, but you can make the data handling an order of magnitude faster by doing block reads:

private byte[] ReadBytesWithSpecifiedLength(int length)
{
    byte[] des = new byte[length];
    serialPort.BaseStream.Read(des, 0, des.Length);
    return des;
}

If you have timeouts enabled, you could get partial reads. Then you need to do something like:

private byte[] ReadBytesWithSpecifiedLength(int length)
{
    byte[] des = new byte[length];
    int recd = 0;
    do {
        int partial = serialPort.BaseStream.Read(des, recd, length - recd);
        if (partial == 0) throw new IOException("Transfer Interrupted");
        recd += partial;
    } while (recd < length);
    return des;
}

The nice thing about BaseStream is that it also has async support (via ReadAsync). That's what new C# code should be using.

Upvotes: 2

Related Questions