非同期処理の練習、Task.Run後におかしな値を返す。

前提

c#のtaskと非同期処理の理解のため、別スレッドに処理を投げるコードを書いてみたのですが意図した結果が得られません。
各ポイントごとにログを出してみたところ、Task.Run()直後からおかしな値を返す挙動をします。

発生している問題

おおまかなログの発生順は意図した通り出力できているのですが、返してくる値がすべて「5」なのが問題です。
私としては「0,1,2,3,4」と出力して欲しいのですが、加算式にもしていないのに何故かループ回数と同じ「5」が5回出力されます。
この「5」に置き換わるタイミングが、Task.Runを使用している箇所HeavyProc()からです。
ここまでの検証で、なぜ「5」が出力されるのか全く見当がつかない状態です。

また、非同期処理なので多少ログの実行順にばらつきが生まれるのは理解できるのですが、色分けの処理がうまく実行されず、緑色から解除されない事が稀にあります。
色を変えてログ処理するメソッドは、すぐに元の色に戻すように書いたつもりですが「非同期処理」においてはこれでは不十分なのでしょうか。
色変えのタイミングに関してはまだ自分の中でも検証が不十分ですので、こういった問題が発生することだけ先に示しておきます。

dotnet run [Main] start... [RunHeavyProcs] i = 0 [RunHeavyProcs] i = 1 [RunHeavyProcs] i = 2 [RunHeavyProcs] i = 3 [RunHeavyProcs] i = 4 [RunHeavyProcs] waiting all-task [HeavyProc] 5 Start... [Main] Finished. [HeavyProc] 5 Start... [HeavyProc] 5 Start... [HeavyProc] 5 Start... [HeavyProc] 5 Start... [RunHeavyProcs] all-task is completed [RunHeavyProcs] r = 5 -- Passed_HeavyProc [RunHeavyProcs] r = 5 -- Passed_HeavyProc [RunHeavyProcs] r = 5 -- Passed_HeavyProc [RunHeavyProcs] r = 5 -- Passed_HeavyProc [RunHeavyProcs] r = 5 -- Passed_HeavyProc

該当のソースコード

cs

using System;using System.Collections.Generic;using System.Threading;using System.Threading.Tasks; /* 非同期処理の練習 https://qiita.com/inew/items/0126270bca99883605de */namespace SushiTabetai{ internal static class Program { // Entry-point static void Main(string[] args) { Console.BackgroundColor = ConsoleColor.Black; Console.ForegroundColor = ConsoleColor.White; WriteLineColor("[Main] start...", ConsoleColor.Yellow); /* async voidを使うと警告がでる場合があるので, 値の破棄"_"を使うと 回避できるかもしれない. 使用する場合は注意. */ _ = RunHeavyProcs(); WriteLineColor("[Main] Finished.", ConsoleColor.Yellow); Console.ReadKey(); } // 重い処理 static string HeavyProc(int x) //static async Task<string> HeavyProc(int x) { WriteLineColor($"[HeavyProc] {x} Start...", ConsoleColor.DarkGreen); Thread.Sleep(2000); //await Task.Delay(2000); return $"{x} -- Passed_HeavyProc"; } static async Task RunHeavyProcs() { //Console.WriteLine("[RunHeavyProcs] ..."); var taskList = new List<Task<string>>(); for (int i = 0; i < 5; i++) { Console.WriteLine("[RunHeavyProcs] i = {0}", i); var _task = Task.Run(() => HeavyProc(i)); taskList.Add(_task); } Console.WriteLine("[RunHeavyProcs] waiting all-task"); await Task.WhenAll(taskList); Console.WriteLine("[RunHeavyProcs] all-task is completed"); for (int i = 0; i < taskList.Count; i++) { Console.WriteLine("[RunHeavyProcs] r = {0}", taskList[i].Result); } } static void WriteLineColor(string str, ConsoleColor col) { var tmpCol = Console.ForegroundColor; Console.ForegroundColor = col; Console.WriteLine(str); Console.ForegroundColor = tmpCol; } }}

長文失礼しました。上記不明点についてご教示いただけたら幸いです。
よろしくお願いいたします。

環境

Visual Studio Code (最新) + C#プラグイン
.NET SDK 6.0.101
(vscode内ターミナルでdotnetコマンドで実行)

コメントを投稿

0 コメント