C# 哪个更快:SerialPort.Write(字节[],int,int)还是SerialPort.BaseStream.WriteByte()?

C# 哪个更快:SerialPort.Write(字节[],int,int)还是SerialPort.BaseStream.WriteByte()?,c#,serial-port,C#,Serial Port,我正在编写一些代码,通过usb上的串行端口控制设备。这个应用程序需要能够在后台运行,同时在端口上持续推送大量数据,因此我需要数据写入代码的速度相当快。我的代码每秒多次大批量推送数据帧。目前,我有一个队列,用于生成需要为当前帧发送的命令。使用SerialPort.BaseStream.Writebyte遍历队列并一次推送一个命令,或者使用队列构建字节数组并使用SerialPort.Writebyte[],int,int一次发送所有命令会更快吗 一些示例代码,如果我的描述令人困惑: 哪个更快,这个:

我正在编写一些代码,通过usb上的串行端口控制设备。这个应用程序需要能够在后台运行,同时在端口上持续推送大量数据,因此我需要数据写入代码的速度相当快。我的代码每秒多次大批量推送数据帧。目前,我有一个队列,用于生成需要为当前帧发送的命令。使用SerialPort.BaseStream.Writebyte遍历队列并一次推送一个命令,或者使用队列构建字节数组并使用SerialPort.Writebyte[],int,int一次发送所有命令会更快吗

一些示例代码,如果我的描述令人困惑: 哪个更快,这个:

   public void PushData(List<KeyValuePair<Address, byte>> data) {
        Queue<DataPushAction> actions = BuildActionQueue(data);
        foreach(var item in actions) {
            port.BaseStream.WriteByte(item.Value);
        }
    }
或者这个:

    public void PushData(List<KeyValuePair<Address, byte>> data) {
        Queue<DataPushAction> actions = BuildActionQueue(data);
        byte[] buffer = actions.Select(x => x.Value).ToArray();
        port.Write(buffer, 0, buffer.Length);
    }
更新

仔细检查源代码后,似乎两个方法都是相同的WriteByte只使用一个元素的临时数组,其他方面与Write相同。然而,这实际上并没有回答这个问题,只是重新表述一下:写入多个小字节数组还是一个大字节数组更快?

基于,它看起来像串行端口。write方法实际上只是指向底层流的write方法:

public void Write(byte[] buffer, int offset, int count)
{
            if (!IsOpen)
                throw new InvalidOperationException(SR.GetString(SR.Port_not_open));
            if (buffer==null)
                throw new ArgumentNullException("buffer", SR.GetString(SR.ArgumentNull_Buffer));
            if (offset < 0)
                throw new ArgumentOutOfRangeException("offset", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNumRequired));
            if (count < 0)
                throw new ArgumentOutOfRangeException("count", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNumRequired));
            if (buffer.Length - offset < count)
                throw new ArgumentException(SR.GetString(SR.Argument_InvalidOffLen));
            if (buffer.Length == 0) return;

            internalSerialStream.Write(buffer, offset, count, writeTimeout);
}
就测试本身而言:

// Create a stopwatch for performance testing
var stopwatch = new Stopwatch();
 // Test content
var data = GetTestingBytes();

// Looping Test
using (var loop = new MemoryStream())
{
      stopwatch.Start();
      foreach (var item in data)
      {
            loop.WriteByte(item);
      }
      stopwatch.Stop();
      Console.WriteLine($"Loop Test: {stopwatch.Elapsed}");
}
// Buffered Test
using (var buffer = new MemoryStream())
{
      stopwatch.Start();
      buffer.Write(data, 0, data.Length);
      stopwatch.Stop();
      Console.WriteLine($"Buffer Test: {stopwatch.Elapsed}");
}
在多次运行测试后,1000次测试后的平均值如下所示:

  LOOP: 00:00:00.0976584
BUFFER: 00:00:00.0976629
因此,循环方法,至少在使用MemoryStream对象的情况下,似乎是赢家


如果你想自己运行它,你可以。通过修改Rion下面答案中的代码,我能够测试这一点并得到一些令人惊讶的结果。我使用了从Rion修改的以下代码,谢谢:

    class Program {
    static void Main(string[] args) {
        // Create a stopwatch for performance testing
        var stopwatch = new Stopwatch();
        // Test content
        var data = GetTestingBytes();

        var ports = SerialPort.GetPortNames();
        using (SerialPort port = new SerialPort(ports[0], 115200, Parity.None, 8, StopBits.One)) {
            port.Open();

            // Looping Test
            stopwatch.Start();
            foreach (var item in data) {
                port.BaseStream.WriteByte(item);
            }
            stopwatch.Stop();
            Console.WriteLine($"Loop Test: {stopwatch.Elapsed}");

            stopwatch.Start();
            port.Write(data, 0, data.Length);
            stopwatch.Stop();
            Console.WriteLine($"All At Once Test: {stopwatch.Elapsed}");
        }

        Console.Read();
    }

    static byte[] GetTestingBytes() {
        var str = String.Join(",", Enumerable.Range(0, 1000).Select(x => Guid.NewGuid()).ToArray());
        byte[] bytes = new byte[str.Length * sizeof(char)];
        System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
        return bytes;
    }
}
结果非常令人惊讶;使用一个字节数组的方法花费的时间几乎是重复调用WriteByte时的6.2935748秒的两倍,为12.5818728秒。这与我预期的结果相反。不管怎样,我都没想到一种方法比另一种快两倍


如果有人能弄明白为什么会这样,我很想知道

我不是在问SerialPort.Writebyte[]与SerialPort.BaseStream.Writebyte[]的关系,我知道它们或多或少是一样的。我的问题是关于使用SerialPort.BaseStream.WriteByte方法,该方法只写入一个字节,并反复调用它。虽然您没有直接回答我的问题,但您确实向我指出了答案。显示WriteByte只使用临时数组,然后执行与正常写入相同的操作。尽管如此,这仍然不能真正回答我的问题,只需重新表述一下:发送几个较小的数组还是一个较大的数组更快?我只是拼凑了一个数组。环路进近采用00:00:00.0005725,而阵列进近采用00:00:00.0005965。您可以很容易地用SerialPorts来扩展相同的测试,但看起来循环速度始终更快。
    class Program {
    static void Main(string[] args) {
        // Create a stopwatch for performance testing
        var stopwatch = new Stopwatch();
        // Test content
        var data = GetTestingBytes();

        var ports = SerialPort.GetPortNames();
        using (SerialPort port = new SerialPort(ports[0], 115200, Parity.None, 8, StopBits.One)) {
            port.Open();

            // Looping Test
            stopwatch.Start();
            foreach (var item in data) {
                port.BaseStream.WriteByte(item);
            }
            stopwatch.Stop();
            Console.WriteLine($"Loop Test: {stopwatch.Elapsed}");

            stopwatch.Start();
            port.Write(data, 0, data.Length);
            stopwatch.Stop();
            Console.WriteLine($"All At Once Test: {stopwatch.Elapsed}");
        }

        Console.Read();
    }

    static byte[] GetTestingBytes() {
        var str = String.Join(",", Enumerable.Range(0, 1000).Select(x => Guid.NewGuid()).ToArray());
        byte[] bytes = new byte[str.Length * sizeof(char)];
        System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
        return bytes;
    }
}