質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

アーキテクチャ

アーキテクチャとは、情報システム(ハードウェア、OS、アプリケーション、ネットワーク等)の設計方法、設計思想、設計思想に基づいて構築されたシステム構造をアーキテクチャと呼びます

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

Q&A

解決済

1回答

1165閲覧

複数機器を制御するアプリケーションのマルチスレッド設計について

退会済みユーザー

退会済みユーザー

総合スコア0

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

アーキテクチャ

アーキテクチャとは、情報システム(ハードウェア、OS、アプリケーション、ネットワーク等)の設計方法、設計思想、設計思想に基づいて構築されたシステム構造をアーキテクチャと呼びます

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

0グッド

0クリップ

投稿2017/08/27 04:08

複数機器を制御するアプリケーションのマルチスレッド設計について

いつもお世話になります。

主題の件について、長文になってしまいますが、ご意見・ご教授をお願い致します。

前提条件

システム要件

例として、以下の図のようなイメージ構成のシステムを考えます。
今回作成するアプリケーションはソフトウェアFOOに該当します。

イメージ説明

このシステムは、以下の動作を行います。

  • FOOは、複数のマシンを制御するアプリケーションである
  • 各マシンは非同期的に動作を行う
  • FOOは各マシンと通信にて制御を行う
  • FOOは基本的にはサーバ的な役割を行う(マシンから通知が来たら、何かしらの処理をして返す)
  • ただし、FOOから能動的に、各マシンへ動作を指示する場合もある
    (例えば、停電発生時に各機器への縮退指示など)
  • 図にはないですが、FOO内の各コントローラは、例えば「電源状態」とか「システムスケジュール」といった共通のステータスを参照する
  • 図にはないですが、マシンAが動いているときは、マシンBは停止するといった、マシン間の制御も行う必要がある
開発環境
  • C#を使用した.NETアプリケーション
現状のソフトウェア設計
  • 各コントローラは1つのコントローラクラスのインスタンスとして、Factoryクラスから生成する

悩んでいる点

ここで、「マシンAのコントローラ」等の、各コントローラでどのように処理を実現すべきか悩んでいます。
具体的に、各コントローラはそれぞれ非同期(ときには同期)で処理を行うことになるのですが、以下の2パターンを構想しています。

<構想1>

  • コントローラクラスを常駐スレッド化する
    →つまり、各コントローラそれぞれに常駐スレッドを設ける
  • インフラストラクチャー層とはスレッド間メッセージキュー等でやり取りして、各マシンの制御を行う

<構想2>

  • コントローラクラスは常駐スレッドを持たない
  • マシンからメッセージを受け取ると、インフラストラクチャー層からコールバックでコントローラへ通知を行い、それをきっかけとして非同期処理を開始し、処理が終わると非同期処理を終了する。
    (イメージとしては、C#でいうと、Task.Run()で非同期処理を行い、各コントローラごとの常駐スレッドはなしで処理を行う)

つまり、構想1・2において、「常駐スレッドをたてる」か「通知が来たときのみ非同期処理を行う」かの違いがあります。

それぞれ、以下の特徴があると考えています。

  • 構想1は、コントローラインスタンスというオブジェクトが、メッセージを受け取ると能動的に処理を行うという点において、オブジェクト指向っぽいやり方である。
    ただし、複数スレッドが常駐するため、全体としての制御が難しい?
  • 構想2は、必要な時に必要なタイミングでマルチスレッドで動作を行うので、スレッドの資源を有効的に使える。
    そして、C#ではマルチスレッド処理はTaskを使用するのが一般的と聞いたので、C#で実現するならこちらのほうが推奨されている?

<補足>ソフトウェアに要求される性能

ソフトウェア的には、パフォーマンスはそこまで要求されません。
どちらかというとメンテナンス性(変更容易性や可読性など)が要求されます。

質問点

  • 上記の構想1・2において、どちらを選択すべきでしょうか。(または他に選択すべき方法があるでしょうか)
    →どちらがメンテナンス性に優れているでしょうか。
  • どちらのやり方が一般的なのでしょうか。

個人的な考えとしては、C#の時流がTaskによる非同期処理なので、構想2が妥当なのかなと思いますが、メンテナンス性や可読性は構想1の方が優れているのかなと感じています。

また、以下の点においてもご意見頂ければ助かります。

  • そもそも、それぞれの構想の特徴の捉え方は間違っていないでしょうか。
  • もし同じような経験をされた方がおられましたら、アドバイス頂けますでしょうか。

以上、長くなりましたが、よろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

こんにちは。

マシンとの通信が状態を持たない単発の1往復で完了し、次の単発との関連がない場合は「構想2」で全体の構造を単純に保つのは好ましいと思います。

しかし、もし、例えば「マシンからA要求がきたら、a応答を返しそのままB要求をサーバ側から送って...」みたいな複雑な通信処理が必要になるなら、その「シーケンス」1つ毎に「スレッド」を割り当てて同期処理した方が見通しはよくなります。

その「シーケンス」がせいぜい2~3ステップ程度の単純なものなら、async関数で実装し、各ステップをawait Task.Runで実装すると楽できます。await Task.Runの前後でコントロールを触れるからなかなか楽です。(例外がApplication.ThreadExceptionに届かないのでちょっとアレですが。)

しかし、async関数はたいへん残念なことに非asyncなメソッドを呼び出してそのメソッドの中でawaitできないのであまり大きな処理を作ることはお勧めしません。(内部で通信するようなメソッド呼び出しを使わないで書いても問題のない程度の処理でないと厳しいです。)

通信制御がそれ以上に複雑になる場合は、構想1のように常駐スレッドを起こすのが良いだろうと感じます。

複数スレッドが常駐するため、全体としての制御が難しい?

常駐スレッドの場合、そのスレッドを終了させる機能が必要になります。きちんと適切に設計できれば簡単なのですが、意外にはまります。マイクロソフトは同期式I/Oに中断機能を設けないことが多いからです。中断させるためだけに非同期I/Oにしないといけないことも度々あります。
VistaでやっとまともにサポートされたI/Oのキャンセル機能

長時間稼働しないスレッドしかないなら、キャンセル処理しないのも選択肢に入るので手間を減らせます。アプリ終了時もちょっと待っている内に終了するのですから。

あとTaskを使う場合は複数のTaskを一度に開始しようとすると遅延が発生するを見ておくと良いかも知れません。
私はこれにはまりました。スレッド起動に数秒かかるとか普通は有り得ないので意外にはまります。

投稿2017/08/27 14:06

編集2017/08/27 14:10
Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/09/02 06:16

回答ありがとうございます。 やはり構想2のほうが構造が単純になるのですね。ここら辺、もともとがC言語上がりなので実際に作ってみないとイメージがわかないのでしょうが、とりあえずは構想2で作っていき、限界を感じたら構想1に切り替えるというつもりでやっていこうと思います。 また、Taskの起動時間に関する情報もありがとうございました。今回のシステムでは例えば同時に10スレッドを生成するということがあるかもしれないので、その際は動作に注視したいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問