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

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

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

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

非同期処理

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

Q&A

解決済

3回答

32371閲覧

UIとは別に非同期で無限ループするクラスの作成方法

kawauso

総合スコア56

C#

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

非同期処理

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

0グッド

1クリップ

投稿2017/08/03 09:56

UIとは別に非同期で無限ループするクラスの作成方法

お世話になっております。
WFPアプリケーションにて、サーバーから値を取得して、処理を行うクラスを作成したいと思っております。
基本的に、アプリが起動してから終了するまでの期間中動作させることを想定しております。

以下のようにしてしまうと、UI側は固まってしまうと思います

csharp

1Class Recv 2{ 3 Recv() 4 { 5 Loop(); 6 } 7 void Loop() 8 { 9 while(true) 10 { 11 int a = GetValue(); // サーバーから値をもらうと仮定 12 a += 10; 13 Console.WriteLine(a); 14 Thread.Sleep(1000); 15 } 16 } 17} 18 19// UI側から 20Recv r = new Recv();

質問
下記のような書き方を行えばUIが固まることはないのですが、問題ないでしょうか。
最適な方法がございましたら、よろしくお願いいたします。

C#

1Task.Run(() => Recv r = new Recv());

C#

1Recv() 2{ 3 Task.Run(() => Loop()); 4}

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

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

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

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

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

guest

回答3

0

こんにちは。

既に解決しているようですが、ちょっと細かい指摘だけしてみます。
UIとは別に無限ループさせるだけなら他回答者さんのやり方で全く問題なく動きます。が、Loop()メソッド自体が同期的に無限ループしているため、「常に1本スレッドを握りしめて継続処理」という形になっているのが気になります。
非同期メソッドを活用することで、ループ処理を定期的なスケジューリングとして実装することができ、資源効率を改善できます。

csharp

1async void Loop() 2{ 3 while(true) 4 { 5 int a = GetValue(); // サーバーから値をもらうと仮定 6 // int a = await GetValueAsync().ConfigureAwait(false); // 普通は外から値を取得(IO)するなら非同期メソッドになるのでは? 7 a += 10; 8 Console.WriteLine(a); 9 await Task.Delay(1000).ConfigureAwait(false); 10 } 11} 12 13// 使う時はただ呼ぶだけ 14Recv() 15{ 16 Loop(); 17}

進行状態等を一切管理しない無限ループだったので戻り値をvoidにしていますが、仮にGetValue()が例外を吐いたりするととても面倒なことになるので、Taskを返すようにしてエラーハンドリング等を実装したほうが良いです。

投稿2017/08/04 01:52

tamoto

総合スコア4103

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

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

kawauso

2017/08/04 02:53

こんにちは。回答ありがとうございます。 非常に勉強になりました。 サーバー側から送られてくる値を取得するところは[こちらのZeroMQ](https://github.com/zeromq/clrzmq4)を使用しています。 ```c# using (var context = new ZContext()) using (var requester = new ZSocket(context, ZSocketType.REQ)) { requester.Connect("tcp://127.0.0.1:5555"); while(true) { var a = requester.ReceiveFrame(); // (1) } } ``` 上記のように書くことで、N秒ごとにサーバーから値が送られてくるとすると、(1)がN秒ごとに呼ばれているようです。 ```ReceiveFrameAsync();```のようなメソッドは見当たりませんでした。 このような場合「常に1本スレッドを握りしめて継続処理」されてしまっているんでしょうか?
tamoto

2017/08/04 04:06

なるほど、見た感じですが、ReceiveFrame()メソッドは「値が送られてくるまでスレッドをブロックして待機」する同期メソッドのように見えますね。これは非同期アクセス用のAPIが提供されていないのであれば、同期メソッドを利用するしかないことになります。 ただし、このコメントのコード例は「受信側で常に1本のスレッドを専有してサーバからのデータの『push』を待機」するものなので、質問のコードのような「一定時間ごとにサーバからデータを『fetch』」するものとは意味合いが異なります。
kawauso

2017/08/04 04:23

ありがとうございます。もう少し勉強してみたいと思います。
guest

0

Task.Run(() => Recv r = new Recv());

このTask.Runはいらないです。

Recvの中でTask.Run()してるのでわざわざ Recvを別スレッドで実行する意味はありません。

C#

1Recv r = new Recv();

C#

1Recv() 2{ 3 Task.Run(() => Loop()); 4} 5

投稿2017/08/03 13:48

Tak1016

総合スコア1408

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

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

kawauso

2017/08/03 23:25

回答、ご指摘ありがとうございます。
guest

0

ベストアンサー

こんにちは。

特に問題ないのではないでしょうか。

あとは通常の非同期処理の注意点を気にすれば良いだけだと思います。

  • UIを操作するときは、UIスレッドで。
  • 共有リソースを扱う場合はスレッドセーフを。

投稿2017/08/03 13:26

Tak1wa

総合スコア4791

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

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

kawauso

2017/08/03 23:26

回答ありがとうございます。 非同期処理の注意点に気をつけて実装していきたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問