System.IO.Ports.SerialPortのRead()とWrite()に時間がかかることがある
解決したいこと
PCの仮想COMポートを使用して外部機器とバイナリ通信を行っているが、ランダムで仮想COMポートへの読み書きに時間がかかることがある。
PC環境
・OS:Windows 10 64bit
・開発環境:Visual Studio Community 2022
・言語:C#
・プロジェクトの種類:Windowsフォームアプリ
・ターゲットフレームワーク:.NET 7.0
・通信パッケージ:System.IO.Ports (7.0.0)
・通信フロー制御:なし
外部機器
・USB UART変換IC:Silicon Labs CP2104
発生している問題・エラー
・System.IO.Ports.SerialPortのRead()とWrite()に時間がかかることがある。
・通常は10msもかからないが、時間がかかるときは必ず約500ms、もしくは約1000msのどちらか。
・System.IO.Ports.SerialPortのReadTimeoutとWriteTimeoutには100msを設定している。
・メインPCより性能の劣るサブPC(Windows 11)だと発生頻度が増える。
該当するソースコード(抜粋)
void Send(SerialPort serialPort, byte[] bytes)
{
var stopwatch = Stopwatch.StartNew();
serialPort.Write(bytes, 0, bytes.Length);
stopwatch.Stop();
if (stopwatch.ElapsedMilliseconds > 10)
{
Debug.WriteLine($"★☆★☆ WriteTime = {stopwatch.ElapsedMilliseconds} ms");
}
}
private void DataReceivedEvent(object sender, SerialDataReceivedEventArgs e)
{
SerialPort serialPort = (SerialPort)sender;
var length = serialPort.BytesToRead;
var bytes = new byte[length];
var stopwatch = Stopwatch.StartNew();
serialPort.Read(bytes, 0, bytes.Length);
stopwatch.Stop();
if (stopwatch.ElapsedMilliseconds > 10)
{
Debug.WriteLine($"★☆★☆ ReadTime = {stopwatch.ElapsedMilliseconds} ms");
}
}
自分で試したこと
・Silicon Labs CP2104のドライバを最新に。
・デバイスマネージャのCOMポートの詳細設定で「FIFOバッファーを使用する」の設定をいろいろ変更。
・System.IO.Ports.SerialPortのRead()とWrite()をlockで囲ってみる。
・System.IO.Ports.SerialPortのRead()とWrite()の前後にTask.Delay()を入れてみる。
・System.IO.Ports.SerialPortのReadTimeoutとWriteTimeoutの設定値を大きくしたり小さくしたり。
追記
PC環境を以下のように変更し、ソースコードもエラーが出る部分は修正して試したところ、Read()とWrite()の処理時間は通常0~20ms、長くても93msに収まっていました。
【変更前】
・プロジェクトの種類:Windowsフォームアプリ
・ターゲットフレームワーク:.NET 7.0
【変更後】
プロジェクトの種類:Windowsフォームアプリケーション(.NET Framework)
ターゲットフレームワーク:.NET Framework 4.8
追記2
ツールを使ってCPUに高負荷をかけると高性能のメインPCでも発生頻度が激増する。ただしサブPCと違って時間は500ms or 1000msではなくランダム。
13:00:55.719 ReadTime = 190 ms
13:00:56.298 ReadTime = 171 ms
13:00:57.287 WriteTime = 484 ms
13:00:58.224 ReadTime = 585 ms
13:00:59.183 WriteTime = 384 ms
13:01:00.413 ReadTime = 724 ms
13:01:01.443 WriteTime = 708 ms
13:01:02.119 ReadTime = 475 ms
13:01:03.302 WriteTime = 965 ms
13:01:04.811 ReadTime = 1116 ms
13:01:07.519 WriteTime = 1523 ms
13:01:10.013 ReadTime = 781 ms
13:01:10.889 WriteTime = 386 ms
「追記」で作成した.NET Framework版に高負荷をかけると以下のようになる。
12:58:31.162 ReadTime = 45 ms
12:58:31.688 ReadTime = 27 ms
12:58:32.214 WriteTime = 47 ms
12:58:32.740 ReadTime = 17 ms
12:58:33.324 ReadTime = 73 ms
12:58:33.845 ReadTime = 22 ms
12:58:34.421 ReadTime = 11 ms
12:58:34.970 ReadTime = 26 ms
12:58:35.798 WriteTime = 56 ms
12:58:37.658 ReadTime = 118 ms
12:58:38.474 WriteTime = 15 ms
12:58:39.678 ReadTime = 96 ms
12:58:40.864 WriteTime = 95 ms
Microsoft製ツール(CpuStres v2.0)
https://learn.microsoft.com/ja-jp/sysinternals/downloads/cpustres