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

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

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

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

LINQ

LINQとはLanguage INtegrated Queryの略で、「統合言語クエリ」という意味です。C#やVisual Basicといった言語のコード内に記述することができるクエリです。

Q&A

解決済

2回答

9970閲覧

C#で並列処理,すべて終わるまで待機

ElecDove

総合スコア254

C#

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

LINQ

LINQとはLanguage INtegrated Queryの略で、「統合言語クエリ」という意味です。C#やVisual Basicといった言語のコード内に記述することができるクエリです。

0グッド

0クリップ

投稿2019/02/04 06:40

編集2019/02/04 07:01

C#で重たい処理を並列処理したいのですが,
全ての処理が終わるまで待機がよくわかりません.

以下のように書いてみたのですが,結果のfuga endが,2endの後ろに来てほしいです.

※Heavy("1")と("2")の中身はそれぞれ独立したものなので排他Lockなどは今のところ必要ありません.

初歩的なことかもしれませんがよろしくお願いします.

C#

1 2static void Main() { 3 fuga(); 4 Console.ReadLine(); 5 } 6 7 static async void fuga() { 8 Console.WriteLine("fuga start"); 9 Task.Run(() => Heavy("1")); 10 Task.Run(() => Heavy("2")); 11 Console.WriteLine("fuga end"); 12 } 13 14 15 static void Heavy(string str) { 16 Console.WriteLine(str + "Start"); 17 for (int i = 0; i < 1000000000; i++) ;//重たい処理 18 Console.WriteLine(str + "End"); 19 } 20
fuga start fuga end 1Start 2Start //ここで数秒待たされる 1End 2End

とりあえずこれで戻り値を拾えましたが会っているのでしょうか…

C#

1static void Main() { 2 3 fuga2(); 4 5 Console.ReadLine(); 6 } 7 8 9 static async void fuga2() { 10 Console.WriteLine("fuga start"); 11 var res = new int[2]; 12 13 14 var tasks = new List<Task<int>>(); 15 tasks.Add(Task.Run(() => Heavy("1"))); 16 tasks.Add(Task.Run(() => Heavy("2"))); 17 await Task.WhenAll(tasks.ToArray()); 18 19 tasks.ForEach(t => Console.WriteLine(t.Result)); 20 21 Console.WriteLine("fuga end"); 22 } 23 24 25 static async Task<int> Heavy(string str) { 26 Console.WriteLine(str + "Start"); 27 for (int i = 0; i < 1000000000; i++) ;//重たい処理 28 Console.WriteLine(str + "End"); 29 30 return 5; //ダミーデータ 31 } 32
fuga start 1Start 2Start //数秒待機 2End 1End 5 5 fuga end

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

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

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

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

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

guest

回答2

0

ベストアンサー

Task.WhenAllですかね。

csharp

1 static async void fuga() { 2 Console.WriteLine("fuga start"); 3 var tasks = new List<Task>(); 4 tasks.Add(Task.Run(() => Heavy("1"))); 5 tasks.Add(Task.Run(() => Heavy("2"))); 6 await Task.WhenAll(tasks.ToArray());; 7 Console.WriteLine("fuga end"); 8 }

投稿2019/02/04 06:44

編集2019/02/04 06:47
papinianus

総合スコア12705

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

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

ElecDove

2019/02/04 06:48

回答ありがとうございます. すいません,takabosoftさんの回答へのコメントを参照お願いします
ElecDove

2019/02/04 06:53

ありがとうございます.ばっちし思い通りに動きました! Task.Run()がキモって事でしょうか... ここで,Heavyの戻り値を受け取りたいと思った場合はどのようになるのでしょうか…?
papinianus

2019/02/04 07:01

キモっていうか、Task型のものを渡してあげないと、takabosoft様のほうに書かれたのは、タスクじゃなくて単にHeavyを実行(引数のHeavy()が評価される)しているにすぎないので。TaskにWrapしていくために、Task.Runがあるわけで。 返り値ってことは `static void Heavy`じゃなくて`static TResult Heavy`ってことですよね? なら ` Task<TResult> task = Task.Run(() => Heavy());` となるはずなので、 `await result = Task.WhenAll(tasks.ToArray());` とするとresultはTResult[]となって、resultの配列からそれぞれの戻り値を得ることができます。
ElecDove

2019/02/04 07:03

回答ありがとうございます. >>単にHeavyを実行(引数のHeavy()が評価される)している 確かにちょっと考えてみればわかることでした 質問を少し編集しましたので合っているかコメントいただけると助かります
papinianus

2019/02/04 07:08 編集

`static async Task<int> Heavy` なら、TaskにWrapしなくていいんで、 task.Add(Heavy(""));です -- task.Add(Task.Run(()=>Heavy("")));としたいなら `static int Heavy` です。 どちらか。 前者で過剰にTaskにWrapしてるから、foreachで取り出さないといけなくなってる。
ElecDove

2019/02/04 07:13 編集

ありがとうございます https://qiita.com/acple@github/items/8f63aacb13de9954c5da こちらによると, >『タスク』を作成し、それを開始したもの」を表します とあります.ということは, async Task<ResType> SomeMethod(){} これは, Task<ResType> task = SomeMethod(); という具合にTask型の変数に代入すると,task変数は「開始したもの」を表すのでしょうか? そしてこれは, Taskでもなんでもない通常のメソッドを Task task = Task.Run(()=>NormalMethod()); という風にしたのとまったく同じ,ということですか?
ElecDove

2019/02/04 07:14

矢継ぎ早ですいません >>前者で過剰にTaskにWrapしてるから、foreachで取り出さないといけなくなってる。 これの意味がよくわからなかったのですが, Task.WhenAllですべてのタスクの終了を待った後にforeachを使わずにtasksからHeavy1,2の結果を取り出せる,ということでしょうか
papinianus

2019/02/04 07:20

2つ目から 質問追記したHeavyはTask<int>なので、tasks.Add(Task.Run(()=>Heavy(""))したときのtasksはList<Task<Task<int>>>です。→過剰にWrap 過剰にWrapしているのでforEachでTask.Resultを使っています。awaitした後にTask型の操作があるのはおかしいです。 Heavyが`static int Heavy(string str)`で、Task.Run(()=>Heavy(""));とすれば await result = Task.WhenAll(tasks);のとき、resultはint[]になります。
papinianus

2019/02/04 07:23

1つめについて、ResTypeの有無がありますが、言いたいこととして「同じかどうか」の点については、認識は合っています。 関数がもともと、Task<T>あるいはTask型の返り値を持つなら、それはT型もしくはvoidの返り値を持つ関数をTask.Run()で包んだのと同じことです。
ElecDove

2019/02/04 07:24

ありがとうございます そういうことだったのですね 大変納得いたしました.
tamoto

2019/02/04 09:27

パット見で横からすみません、コメントに対してですが、Task.RunはFunc<Task<T>>を取るオーバーロードを持ってたはずなのでtasks.Add(Task.Run(()=>Heavy(""))は正しくList<Task<int>>になってませんか? まあそれはおいといて、無意味な二重ラップは避けるべきなのは間違いないですです。
ElecDove

2019/02/04 09:59

tamatoさん,確認しました. tasks.add(Task.Run(()=>Heavy("1"))); のRunにオンマウスで確認したところ Task<int> Task.Run<int>(Func<Task<int>>function) と,確かになっていました
ElecDove

2019/02/04 10:39 編集

となると疑問なのですが, var result = Task.WhenAll(tasks.Toarray()); とした後に, resultはint[]になっているので想定通りなのですが, tasks.resultもintです. tasksはList<Task<int>>なので,tasks.foreach(t=>t.result); とすれば欲しかったint型の答えが手に入れられるのですが,後者は間違っている?ということでしょうか →https://teratail.com/questions/172609 こちらの質問で回答いただきました.質問の本質としては同じ内容でした.
guest

0

C# Taskの待ちかた集によると

await Task.WhenAll(...)

でどうでしょうか?

投稿2019/02/04 06:44

takabosoft

総合スコア8356

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

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

ElecDove

2019/02/04 06:47

回答ありがとうございます. こちらのソースであっていますでしょうか. ```C# static void Main() { fuga(); Console.ReadLine(); } static async void fuga() { Console.WriteLine("fuga start"); await Task.WhenAll(Heavy("1"), Heavy("2")); Console.WriteLine("fuga end"); } static async Task Heavy(string str) { Console.WriteLine(str + "Start"); for (int i = 0; i < 1000000000; i++) ;//重たい処理 Console.WriteLine(str + "End"); } ``` これの実行結果は ```結果 fuga start 1Start //ここで数秒待たされる 1End 2Start //ここで数秒待たされる 2End fuga end ``` となってしまいます・・・
takabosoft

2019/02/04 06:51

await Task.WhenAll(Task.Run(() => Heavy("1")), Task.Run(() => Heavy("2"))); じゃないですかね。
papinianus

2019/02/04 06:51

1Start, 2Start, 待ち、となりたいという意味でしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問