Javaのシリアルポート送受信を、イベントを用いた場合と、ユーザが無限ループを組んで行った場合、それぞれのCPU負荷を比較してみた。
検証環境
・Ubuntu 14.0 4LTS
・Java 8
・rxtxライブラリ version 2.1
CPU負荷測定結果
無限ループを用いた場合で、Readlineを用いた場合のCPU負荷
やはり、イベントを用いたほうが遥かにCPU負荷が低く、好ましい結果となっている
イベント serialEvent を用いた場合
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import gnu.io.CommPortIdentifier; import gnu.io.SerialPort; import gnu.io.SerialPortEvent; import gnu.io.SerialPortEventListener; /** * シリアルポート送受信のテスト・クラス。受信イベントを用いてCPU負荷を低減した版 * */ public class main_class implements SerialPortEventListener { private static CommPortIdentifier comID; private static SerialPort commPort; BufferedReader in; private static BufferedReader br; Boolean flagDispDisable = false; /** * このmain_classのコンストラクタ。 シリアルポートのデバイス名と通信速度のユーザ入力と、シリアルポートを開く処理 */ public main_class() { // シリアルポートのデバイス名と通信速度のユーザ入力 String commDeviceName = "/dev/ttyUSB0"; int commSpeed = 9600; br = new BufferedReader(new InputStreamReader(System.in)); try { System.out.print("comデバイス名 (/dev/ttyUSB0) : "); commDeviceName = br.readLine(); if (commDeviceName.length() < 1) commDeviceName = "/dev/ttyUSB0"; System.out.print("通信速度 bps (9600) : "); String strTemp = br.readLine(); if (strTemp.length() < 1) commSpeed = 9600; else commSpeed = Integer.parseInt(strTemp); if (commSpeed != 2400 && commSpeed != 4800 && commSpeed != 9600 && commSpeed != 14400 && commSpeed != 19200) commSpeed = 9600; } catch (IOException e) { e.printStackTrace(); System.out.println("\nkeyboard input error"); return; } // シリアルポートを開き、通信速度等を設定する try { comID = CommPortIdentifier.getPortIdentifier(commDeviceName); commPort = (SerialPort) comID.open("dummy_app_name", 2000); commPort.setSerialPortParams(commSpeed, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); commPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE); } catch (Exception e) { e.printStackTrace(); System.out.print("\ncomm port open error\n"); if (commPort != null) commPort.close(); return; } // シリアルポートで発生するイベント処理の初期設定 try { commPort.addEventListener(this); commPort.notifyOnDataAvailable(true); commPort.notifyOnBreakInterrupt(true); // 指定したバイト以上受信したらEventを発生させる commPort.enableReceiveThreshold(5); // 指定したミリ秒が経過すれば強制的にEventを発生させる commPort.enableReceiveTimeout(500); } catch (Exception e) { e.printStackTrace(); } // シリアルポート受信側ストリームを開く try { in = new BufferedReader(new InputStreamReader( commPort.getInputStream())); } catch (IOException e) { e.printStackTrace(); } } /** * ユーザのキーボード入力でシリアルポートに送信するループ */ private void main_loop() { OutputStream outStream; try { // シリアルポート送信側ストリームを開く outStream = commPort.getOutputStream(); while (true) { // 端末で1行入力 String tmpStr = br.readLine(); // このプログラムを終了する if (tmpStr.equalsIgnoreCase("quit") || tmpStr.equalsIgnoreCase("exit") || tmpStr.equalsIgnoreCase("q")) break; else if (tmpStr.length() < 1) { // シリアルポートで受信したデータを表示するかどうかのトグル flagDispDisable = !flagDispDisable; if (flagDispDisable) System.out .println("(disp off) command -> quit, spdNNNN"); } else if (tmpStr.equalsIgnoreCase("spd4800")) { // シリアルポートへの送信(通信速度設定) outStream.write("spd4800\r".getBytes()); System.out.println("Send command \"speed 4800 bps\""); } else if (tmpStr.equalsIgnoreCase("spd9600")) { outStream.write("spd9600\r".getBytes()); System.out.println("Send command \"speed 9600 bps\""); } else if (tmpStr.equalsIgnoreCase("spd19200")) { outStream.write("spd19200\r".getBytes()); System.out.println("Send command \"speed 19200 bps\""); } else if (tmpStr.equalsIgnoreCase("stop")) { // シリアルポートへの送信(一時停止コマンド) outStream.write("stop\r".getBytes()); System.out.println("Send command \"stop\""); } else System.out.println("command error"); } System.out.print("exit read loop\n"); // シリアルポートの受信側ストリームを閉じる in.close(); System.out.print("commPort BufferedReader is closed\n"); // シリアルポートの送信側ストリームを閉じる outStream.close(); System.out.print("commPort OutputStream is closed\n"); } catch (IOException e) { e.printStackTrace(); } finally { try { // シリアルポートを閉じる commPort.close(); System.out.print("commPort is closed\n"); // キーボード入力を閉じる br.close(); System.out.print("Keyboard input stream is closed\n"); } catch (IOException e) { e.printStackTrace(); } } } /** * Javaプログラムの開始関数 main * * @param args */ public static void main(String[] args) { System.out.println("シリアル通信(送受信) イベント利用版"); // クラスを初期化(シリアルポートを開く) main_class serial_main = new main_class(); // ユーザのキーボード入力でシリアルポートに送信するループ serial_main.main_loop(); } /* * シリアルポートで発生するイベント受信 * * @see gnu.io.SerialPortEventListener#serialEvent(gnu.io.SerialPortEvent) */ @Override public void serialEvent(SerialPortEvent arg0) { if (arg0.getEventType() == SerialPortEvent.DATA_AVAILABLE) { try { // シリアルポートから1行(末尾改行)テキストを読み込み画面表示 String inputLine; if ((in.ready()) && (inputLine = in.readLine()) != null) { if (!flagDispDisable) System.out.println(inputLine); } } catch (IOException e) { e.printStackTrace(); } } } }
無限ループを用いた場合
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import gnu.io.CommPortIdentifier; import gnu.io.SerialPort; /** * シリアルポート送受信のテスト・クラス。受信イベントを用いず、ループ処理でCPU負荷が高い版 * */ public class main_class { private static CommPortIdentifier comID; private static SerialPort commPort; private static BufferedReader br; /** * Javaプログラムの開始関数 main * * @param args */ public static void main(String[] args) { System.out.println("シリアル通信(送受信) 受信無限ループ待ち版"); // シリアルポートのデバイス名と通信速度のユーザ入力 String commDeviceName = "/dev/ttyUSB0"; int commSpeed = 9600; br = new BufferedReader(new InputStreamReader(System.in)); try { System.out.print("comデバイス名 (/dev/ttyUSB0) : "); commDeviceName = br.readLine(); if (commDeviceName.length() < 1) commDeviceName = "/dev/ttyUSB0"; System.out.print("通信速度 bps (9600) : "); String strTemp = br.readLine(); if (strTemp.length() < 1) commSpeed = 9600; else commSpeed = Integer.parseInt(strTemp); if (commSpeed != 2400 && commSpeed != 4800 && commSpeed != 9600 && commSpeed != 14400 && commSpeed != 19200) commSpeed = 9600; } catch (IOException e) { e.printStackTrace(); System.out.println("\nkeyboard input error"); return; } // シリアルポートを開き、通信速度等を設定する try { comID = CommPortIdentifier.getPortIdentifier(commDeviceName); commPort = (SerialPort) comID.open("dummy_app_name", 2000); commPort.setSerialPortParams(commSpeed, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); commPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE); } catch (Exception e) { e.printStackTrace(); System.out.print("\ncomm port open error\n"); if (commPort != null) commPort.close(); return; } // シリアルポートからの受信を1行毎(Readline関数)を用いる場合 Receive_Readline(); // シリアルポートからの受信を1文字毎(Read関数)を用いる場合 // Receive_Read(); } /** * シリアルポートからの受信を1行毎(Readline関数)に画面表示し、 端末キーボードからの入力をシリアルポート側に送信する。 */ private static void Receive_Readline() { BufferedReader in; OutputStream outStream; Boolean flagDispDisable = false; try { // シリアルポート受信側ストリームを開く in = new BufferedReader(new InputStreamReader( commPort.getInputStream())); // シリアルポート送信側ストリームを開く outStream = commPort.getOutputStream(); // シリアルポート受信、端末キーボード入力の無限ループによる処理 String inputLine; while (true) { // シリアルポートから1行(末尾改行)テキストを読み込み画面表示 if ((in.ready()) && (inputLine = in.readLine()) != null) { if (!flagDispDisable) System.out.println(inputLine); } // 端末のキーボード入力を待ち、シリアルポート側へ送信する if (br.ready()) { String tmpStr = br.readLine(); // このプログラムを終了する if (tmpStr.equalsIgnoreCase("quit") || tmpStr.equalsIgnoreCase("exit") || tmpStr.equalsIgnoreCase("q")) break; else if (tmpStr.length() < 1) { // シリアルポートで受信したデータを表示するかどうかのトグル flagDispDisable = !flagDispDisable; if (flagDispDisable) System.out .println("(disp off) command -> quit, spdNNNN"); } else if (tmpStr.equalsIgnoreCase("spd4800")) { // シリアルポートへの送信(通信速度設定) outStream.write("spd4800\r".getBytes()); System.out.println("Send command \"speed 4800 bps\""); } else if (tmpStr.equalsIgnoreCase("spd9600")) { outStream.write("spd9600\r".getBytes()); System.out.println("Send command \"speed 9600 bps\""); } else if (tmpStr.equalsIgnoreCase("spd19200")) { outStream.write("spd19200\r".getBytes()); System.out.println("Send command \"speed 19200 bps\""); } else if (tmpStr.equalsIgnoreCase("stop")) { // シリアルポートへの送信(一時停止コマンド) outStream.write("stop\r".getBytes()); System.out.println("Send command \"stop\""); } else System.out.println("command error"); } } System.out.print("exit read loop\n"); // シリアルポートの受信側ストリームを閉じる in.close(); System.out.print("commPort BufferedReader is closed\n"); // シリアルポートの送信側ストリームを閉じる outStream.close(); System.out.print("commPort OutputStream is closed\n"); } catch (IOException e) { System.out.print("read error\n"); e.printStackTrace(); } finally { try { // シリアルポートを閉じる commPort.close(); System.out.print("commPort is closed\n"); // キーボード入力を閉じる br.close(); System.out.print("Keyboard input stream is closed\n"); } catch (IOException e) { e.printStackTrace(); } } } /** * シリアルポートからの受信を1文字毎(Read関数)に画面表示し、 端末キーボードからの入力をシリアルポート側に送信する。 */ private static void Receive_Read() { BufferedReader in; OutputStream outStream; Boolean flagDispDisable = false; try { // シリアルポート受信側ストリームを開く in = new BufferedReader(new InputStreamReader( commPort.getInputStream())); // シリアルポート送信側ストリームを開く outStream = commPort.getOutputStream(); // シリアルポート受信、端末キーボード入力の無限ループによる処理 String inputLine = ""; int inputChar; while (true) { // シリアルポートから1行(末尾改行)テキストを読み込み画面表示 if ((in.ready()) && (inputChar = in.read()) != -1) { // 受信すべき文字の範囲はASCII文字のみ if (0x20 <= inputChar && inputChar <= 0x7e) inputLine += (char) inputChar; // 改行文字が来たら、また1行が256文字を超えれば画面表示 else if (inputChar == 0x0d || inputLine.length() >= 256) { if (!flagDispDisable) System.out.println(inputLine); inputLine = ""; } } // 端末のキーボード入力を待ち、シリアルポート側へ送信する if (br.ready()) { String tmpStr = br.readLine(); // このプログラムを終了する if (tmpStr.equalsIgnoreCase("quit") || tmpStr.equalsIgnoreCase("exit") || tmpStr.equalsIgnoreCase("q")) break; else if (tmpStr.length() < 1) { // シリアルポートで受信したデータを表示するかどうかのトグル flagDispDisable = !flagDispDisable; if (flagDispDisable) System.out .println("(disp off) command -> quit, spdNNNN"); } else if (tmpStr.equalsIgnoreCase("spd4800")) { // シリアルポートへの送信(通信速度設定) outStream.write("spd4800\r".getBytes()); System.out.println("Send command \"speed 4800 bps\""); } else if (tmpStr.equalsIgnoreCase("spd9600")) { outStream.write("spd9600\r".getBytes()); System.out.println("Send command \"speed 9600 bps\""); } else if (tmpStr.equalsIgnoreCase("spd19200")) { outStream.write("spd19200\r".getBytes()); System.out.println("Send command \"speed 19200 bps\""); } else if (tmpStr.equalsIgnoreCase("stop")) { // シリアルポートへの送信(一時停止コマンド) outStream.write("stop\r".getBytes()); System.out.println("Send command \"stop\""); } else System.out.println("command error"); } } System.out.print("exit read loop\n"); // シリアルポートの受信側ストリームを閉じる in.close(); System.out.print("commPort BufferedReader is closed\n"); // シリアルポートの送信側ストリームを閉じる outStream.close(); System.out.print("commPort OutputStream is closed\n"); } catch (IOException e) { System.out.print("read error\n"); e.printStackTrace(); } finally { try { // シリアルポートを閉じる commPort.close(); System.out.print("commPort is closed\n"); // キーボード入力を閉じる br.close(); System.out.print("Keyboard input stream is closed\n"); } catch (IOException e) { e.printStackTrace(); } } } }