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