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

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

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

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

Q&A

解決済

2回答

1133閲覧

C#のAsyncにおいて、Async宣言されていない処理を非同期処理の中に組み込む方法

Tsudanuma

総合スコア5

C#

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

0グッド

0クリップ

投稿2021/12/09 13:45

知りたいこと

C#のasyncの機能ですが、普通のasync宣言されていない関数は非同期処理することはできないのでしょうか。例えば、下記コードにおいては、クラスAについて非同期を実装したいのですが、調べたところによるとどうにもA, B, C, DすべてのRunについてasyncとawaitをつけなければいけないように見受けられます。しかし、どうにも理にかなっていないように思います。C#で用意されているライブラリのほとんどは同期処理を前提としているはずで、非同期処理を行いたければそれらを使用できないのでしょうか。なにか私が見落としていることがありましたら教えてください。

C#

1class Program 2{ 3 static void Main(string[] args) 4 { 5 A.Run(); 6 } 7} 8public static A 9{ 10 public void Run() 11 { 12 B.Run(); 13 } 14} 15public static B 16{ 17 public void Run() 18 { 19 C.Run(); 20 } 21} 22public static C 23{ 24 public void Run() 25 { 26 D.Run(); 27 } 28} 29......

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

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

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

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

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

Zuishin

2021/12/09 13:50

非同期メソッドの中から同期メソッドを呼び出すことはできます。 何を聞いているのかよくわかりません。
Tsudanuma

2021/12/09 13:58

例えば、Aにasyncをつけてawait A.Run();とすると、A.Runの中にもawaitをつけることを要求されます。A.Runの処理はB.Runですので、await B.Run();とする必要が出てきます。こうすると、A~ZまでクラスがあるとしてZまで書き直す必要に迫られます。これの対処法をお伺いしています。
退会済みユーザー

退会済みユーザー

2021/12/09 13:59

A.Run とか B.Run って何ですか? あなたの言う同期処理と非同期処理の定義は何ですか? async / await とあなたの言う「非同期処理」はどう関係すると思っていますか? 「どうにも理にかなっていないように思います」とありますが何が理にかなってないのですか? 「C#で用意されているライブラリのほとんどは同期処理を前提としている」とは何を見てそう言ってるのが具体例を挙げられますか? 少し勉強してから質問しないと話が通じないと思いますけど・・・
Tsudanuma

2021/12/09 14:10

SurferOnWwwさん、失礼しました。非同期処理と同期処理で関数を全て分けるのはおかしいと思い、その反例として同期処理を前提としているとお話ししました。そもそも、非同期処理と同期処理の処理が分かれていないのであればこの話はつじつまがあいませんので、誤解を招きました。平たく言いますと、「用意されている普通の関数を、非同期処理する方法」をお伺いしています。よろしければ、ご回答いただけますでしょうか。
Tsudanuma

2021/12/09 14:16

色々いじってたらできました。ありがとうございます
退会済みユーザー

退会済みユーザー

2021/12/09 14:22

何ができたのですか? あなたの質問のコードを見る限り何もできないと思いますけど。何をどのようにできたのか、回答欄に具体的に、あくまで具体的に、ここに書いてないこと以外は知り得ない第三者が読んで分かるように文書化できますか?
dodox86

2021/12/10 00:10

現状ですと質問の意義も分からず回答もつかず無価値なものとなり、放置しておくと低評価が重なることが予想されます。質問は取り下げ(削除依頼)できますので、何らかの対応をすることをお勧めします。 [質問・回答を消去したい] https://teratail.com/help#delete-question
guest

回答2

0

質問者さんは自己解決済だそうなのでアレですが、せっかくレスを書いたので載せておきます。

まず、質問者さんの言う同期・非同期の意味ですが、以下のようなことと理解します。

同期: メインスレッド一つだけでプログラムに書かれた順に実行していく。

非同期: プログラムの中のある処理をメインスレッドとは別のスレッドで実行する。

普通のasync宣言されていない関数は非同期処理することはできないのでしょうか。

できます。以下の例を見てください。VS2022 で作った .NET 6.0 ベースの WinForms アプリです。非同期により UI スレッドがブロックされないという効果が分かりやすいので GUI アプリにしています。

namespace WinFormsApp2 { public partial class Form2 : Form { public Form2() { InitializeComponent(); } // 非同期メソッド TimeCosumingMethod1 を呼び出す private async void button1_Click(object sender, EventArgs e) { label1.Text = $"メインスレッド ID: {Thread.CurrentThread.ManagedThreadId} / "; label2.Text = ""; label2.Text = await TimeCosumingMethod1(); label1.Text += Thread.CurrentThread.ManagedThreadId; } // 同期メソッド TimeCosumingMethod2 を呼び出す private async void button2_Click(object sender, EventArgs e) { label1.Text = $"メインスレッド ID: {Thread.CurrentThread.ManagedThreadId} / "; label2.Text = ""; label2.Text = await Task.Run(() => TimeCosumingMethod2()); label1.Text += Thread.CurrentThread.ManagedThreadId; } // 非同期メソッド private async Task<string> TimeCosumingMethod1() { string s = $"TimeCosumingMethod1 スレッド ID: {Thread.CurrentThread.ManagedThreadId} IN / "; await Task.Delay(3000); return s + $"{Thread.CurrentThread.ManagedThreadId} OUT"; } // 昔ながらの同期メソッド private string TimeCosumingMethod2() { string s = $"TimeCosumingMethod2 スレッド ID: {Thread.CurrentThread.ManagedThreadId} IN / "; Thread.Sleep(3000); return s + $"{Thread.CurrentThread.ManagedThreadId} OUT"; } } }

上のコードの中の TimeCosumingMethod2 が昔ながらの同期メソッドですが、Task.Run を使って別スレッドで動かしているので UI はブロックされません。

イメージ説明

asyncとawaitをつけなければいけないように見受けられます。

async / await の説明については、自分的には以下の記事が分かりやすかったので紹介しておきます。

第2回 非同期メソッドの構文
https://atmarkit.itmedia.co.jp/fdotnet/chushin/masterasync_02/masterasync_02_01.html

記事を読んでもらえばわかると思いますが、async / await を付与することにより非同期になるという訳ではないのです。

記事の抜粋ですが、

"async修飾子は、修飾したメソッド内でawait演算子(後述)を利用するためのキーワードだ。asyncキーワードは単にメソッドの修飾でしかなく、これを加えたことによってコンパイル結果として何かが展開されたりすることはない"

"await演算子の意味は、「待っているタスクがまだ完了していない場合、メソッドの残りをそのタスクの『継続』として登録して呼び出し元に処理を戻し、タスクが完了したら登録しておいた継続処理を実行すること」なので注意が必要だ"

なお、質問者さんが回答欄に自己解決として載せたコードは、回答のコメントにも書きましたがコンパイルも通らないはずですし、そこを A.RunAsync(); に直したとしても await が付与してないので、メインスレッドと別スレッドで勝手に走って行って、コンソールへの書き込みが期待した結果にならないはずです。

以下のようにしないとダメかと。

namespace ConsoleApp1 { internal class Program { static async Task Main(string[] args) { await A.RunAsync(); Console.WriteLine("今日は世界!"); } } public class A { public static async Task RunAsync() { Task t1 = Task.Run(() => { Thread.Sleep(3000); Console.WriteLine("Hello World!"); }); await t1; } } }

ちなみに上のコードで await A.RunAsync(); の await を外すとコンソールには「今日は世界!」だけ表示されてアプリケーションは終了してしまいます。

投稿2021/12/10 05:54

編集2021/12/10 06:25
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

0

自己解決

単純に非同期で関数を動かす方法をうかがうべきでした。わかったやり方は下記に示します。asyncとsyncが交互に表示されるのがわかるので、直感でわかりやすいです。

C3

1class Program 2{ 3 static void Main(string[] args) 4 { 5 A.RunAsync; 6 for(int i=0; i<10000; i++) 7 Console.WriteLine("sync executed!!!"); 8 } 9} 10public class A 11{ 12 public static async Task RunAsync() 13 { 14 Task t1 = Task.Run(()=> 15 { 16 for(int i=0; i<10000; i++) 17 Console.WriteLine("async executed!!!"); 18 }); 19 await t1; 20 } 21}

投稿2021/12/10 04:02

Tsudanuma

総合スコア5

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

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

退会済みユーザー

退会済みユーザー

2021/12/10 05:41 編集

A.RunAsync; ではコンパイルも通らないのでは? A.RunAsync(); としても await を付与するよう警告が出るはず。await 無しでも実行はできるかもしれませんが、メインスレッドと別スレッドで勝手に走って行って、コンソールへの書き込みが期待した結果にならないのでは? ↓ 読んでみましょう。特に「すべて非同期にする」のセクション。 非同期プログラミングのベスト プラクティス https://docs.microsoft.com/ja-jp/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問