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

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

新規登録して質問してみよう
ただいま回答率
85.35%
CPU

CPUは、コンピュータの中心となる処理装置(プロセッサ)で中央処理装置とも呼ばれています。プログラム演算や数値計算、その他の演算ユニットをコントロール。スマホやPCによって内蔵されているCPUは異なりますが、処理性能が早いほど良いとされています。

C#

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

非同期処理

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

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Q&A

解決済

2回答

873閲覧

メソッド内で生成される値を、別のメソッドで非同期で受け取りたい

test189

総合スコア1

CPU

CPUは、コンピュータの中心となる処理装置(プロセッサ)で中央処理装置とも呼ばれています。プログラム演算や数値計算、その他の演算ユニットをコントロール。スマホやPCによって内蔵されているCPUは異なりますが、処理性能が早いほど良いとされています。

C#

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

非同期処理

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

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

0グッド

1クリップ

投稿2020/11/14 11:36

編集2020/11/15 05:48

前提・実現したいこと

以下のソースコードにおいて、
メソッドHogehoge内で生成される値barを、Btn_Click内の処理で随時取得したく、
メソッドGetValueAsyncを作成したのですが、
GetValueAsync内のwhileループでCPU使用率がとても高くなってしまいます。

該当のソースコード

csharp

1 2private string _foo; 3 4private async task Hogehoge() 5{ 6 while(条件式) 7 { 8 ... 9 this._foo = bar; // barはこのHogehoge内で生成される値 10 } 11 ... 12} 13 14private async Task<string> GetValueAsync() 15{ 16 var value = await Task.Run(() => 17 { 18 while (true) 19 { 20 if (this._foo != null) 21 return this._foo; 22 } 23 }); 24 25 this._foo = null; 26 27 return value; 28} 29 30public async void Btn_Click(object sender, RoutedEventArgs e) 31{ 32 while(true) 33 { 34 Debug.WriteLine(await GetValueAsync()); 35 } 36}

試したこと

以下のように、Task.Delay(1)を入れるとCPU使用率が上がることがなくなったのですが、
こんな解決策でよいのか(そもそもなぜこれで解決するのか)、またもっと他に良い方法がないかと思っています。

詳しい方おられましたら、ご教授お願いいたします。

csharp

1private async Task<string> GetValueAsync() 2{ 3 var value = await Task.Run(async () => 4 { 5 while (true) 6 { 7 await Task.Delay(1); // これを追加 8 if (this._foo != null) 9 return this._foo; 10 } 11 }); 12 13 this._foo = null; 14 15 return value; 16} 17

補足(実現したいこと)

barの値の取得に関してですが、
Btn_Click内でGetValueAsyncが呼ばれたタイミングのbarの値が取得できればそれでいいです。
Btn_Click内でGetValueAsyncが呼ばれたタイミングのbarの値(ただし、barが更新されていなければ、更新されるまで待つ)を取得したいです。

解決策?

いただいた回答に基づいて、コードを改良してみました。

csharp

1 2private readonly AutoResetEvent condition = new AutoResetEvent(false); 3 4private async Task<string> GetValueAsync() 5{ 6 await Task.Run(() => 7 { 8 condition.WaitOne(); 9 }); 10 return this._originaltext; 11} 12

Hogehogeメソッドのとこには、
this._foo = bar;の下に、condition.Set();を記述。

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2020/11/15 05:03 編集

ループを回している間は、該当スレッドがループを回すという仕事をし続けているのでCPUを使用します。SleepやDelayはOSに処理を返すためCPUを占有しません。
test189

2020/11/15 05:11

なるほど、そうなんですね。ありがとうございます。 ちなみに、スレッドがブロックされるのを回避するために「特に待つ必要はないけれどもwhileループの中にawait Task.Delayを入れ込む」というような書き方は、そもそもプログラムの書き方がやはりおかしいのでしょうか。
guest

回答2

0

whileループで待つようなことはせず、
AutoResetEvent などの同期イベントを使いましょう

AutoResetEvent クラス (System.Threading) | Microsoft Docs

投稿2020/11/14 13:19

y_waiwai

総合スコア88042

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

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

test189

2020/11/14 16:41

コメントありがとうございます。 AutoResetEventというものを初めて知りました。 これを使って書き換えてみると、cpu使用率も特に上昇せず期待通りに動きました。 ちなみに書き方ですが、上のような書き方で問題ないでしょうか。
guest

0

ベストアンサー

メソッドHogehoge内で生成される値barを、Btn_Click内の処理で随時取得したく、メソッドGetValueAsyncを作成したのですが、

private string _foo; と private async task Hogehoge() は何らかのクラスに属していると思いますが、であればそのクラスに _foo の値を返すプロパティを追加して、それ経由で取得してはいかがですか?

コードは以下のような感じ。(変数、メソッドの名前等は質問のコードから変えてます)

using System; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsAsyncTest { public partial class Form6 : Form { private MyClass myClass; public Form6() { InitializeComponent(); } private async void button1_Click(object sender, EventArgs e) { this.myClass = new MyClass(); await this.myClass.MyAsyncMethod(); } private void button2_Click(object sender, EventArgs e) { if (this.myClass != null) { this.label1.Text = this.myClass.Value; } } } public class MyClass { private string _value; public string Value { get { return _value; } } public async Task MyAsyncMethod() { // 取りあえず 100 を上限 int i = 0; while (i < 100) { // なんらかの処置と bar の生成 // Task.Delay(100) と i で代用 await Task.Delay(100); string bar = "Bar の値: " + i; this._value = bar; i++; } } } }

結果は以下の通りです。

![イメージ説明]

投稿2020/11/15 03:49

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

test189

2020/11/15 05:14

コードまで書いていただき、ご回答ありがとうございます。 説明不足で申し訳ないのですが、 Btn_Clickの中でwhileループなどでずっとmyClass.Valueの値を読みたいのですが、 MyAsyncMethodのwhileループ内でthis._valueの値が更新されたときに読み込みたいので、y_waiwaiさんがおっしゃられてるようなAutoResetEventのようなシグナル?を使った手段が適切なのかなと思いました。
退会済みユーザー

退会済みユーザー

2020/11/15 05:27 編集

> MyAsyncMethodのwhileループ内でthis._valueの値が更新されたときに読み込みたい それは話が違うような気がしますけど? 質問には、 > Btn_Click内でGetValueAsyncが呼ばれたタイミングのbarの値が取得できればそれでいいです。 と書いてありましたが・・・ > AutoResetEventのようなシグナル?を使った手段が適切なのかなと思いました。 同期コードと非同期コードを混在させることによるデッドロックの問題とかはないのでしょうか? 以下のドキュメントにあるように「すべて非同期にする」のが基本だと思っているのですが・・・ 非同期プログラミングのベスト プラクティス https://docs.microsoft.com/ja-jp/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
test189

2020/11/15 05:45

質問が不適切で、申し訳ありませんでした。 正しくは「Btn_Click内でGetValueAsyncが呼ばれたタイミングのbarの値(ただし、barが更新されていなければ、更新されるまで待つ)を取得したい」になります。 質問文も編集しておきます。 非同期のベストプラクティス挙げていただきありがとうございます。 なかなか難しいですが、じっくり考えてみたいと思います。
退会済みユーザー

退会済みユーザー

2020/11/15 08:54

いつまで待っても更新されないと破綻しそうなのでキャンセルできるようにしないとダメかもしれませんね。イベントとそれを処理するコールバックで行うことも考えてみてはどうでしょう?
test189

2020/11/15 15:26

>いつまで待っても更新されないと破綻しそうなので... そうですね、まさにそこがネックですが、イベント処理の方法を調べてやってみたいと思います。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問