参考にしたサイトは下記になります。
https://www.kekyo.net/2015/06/04/4735
また、async-awaitの使い方を調べていてこの記事にたどり着いた場合は、「基本的にTask.Runは使わない」と言う事を頭の片隅に置いておいて下さい。特殊な場合を除いて、明示的にTask.Runでワーカースレッドを操作する必要はありません。非同期メソッドが返すTaskクラスをawaitする事に集中すれば、問題なくコードを記述できる筈です。
https://www.kekyo.net/2016/12/06/6186
Task.Run()とか、Task.Factory.StartNew()とか、Task.Start()とか、Task.ContinueWith()を使ってるコードを頻繁に見る(不要なのに)。
ここまで、Task.Run()も、Task.Factory.StartNew()も、Task.Start()も、Task.ContinueWith()も、Task.Wait()も、Task.Resultも出ませんでしたね? これらを使う事はまずありません(断言)。
と記載していますが、記事内ではHTTPClientのReadFromUrlAsync()を利用しているためReadFromUrlAsync()が内部でTask.Runを行って非同期処理になっているだけに見えます。
(ReadFromUrlAsync()を使用した検証はまだ行えていません)
そもそもasyncとawaitだけを書いても自作メソッドでは最終的にawaitを書く事が出来ず「CS1998:この非同期メソッドにはawait演算子がないため、同期的に実行されます」の警告が出ます。
Task.Run()を使わないと非同期処理が出来ないか一瞬で抜ける挙動しか私には書けません。
また、下記の検証用コードではTask.Runを使用していなければどれだけasync-awaitを記述しようが同期処理しているように見えます。
Form内のListViewへファイルをドロップし、txtファイルであればlistviewへ列挙して処理開始と終了をRichTextBoxへ記入するという挙動で作成しました。
Formアプリケーションで非同期処理を行っている間はControlを触るとエラー落ちするため、InvokeRequiredでInvokeの要不要を確認し、エラー回避を行っていますがこのコードでも私の推測と同じ挙動を示しています。
また大量のファイルをあえてドロップする事でFormが固まるかも確認しましたが、Task.Runを使用した場合のみFormが固まりませんでした。
使用Controlは
Form Form1
ListView listViewTextList
RichTextBox richTextBoxResult(AllowDrop = True)
です
C#
1 public Form1() 2 { 3 InitializeComponent(); 4 } 5 //Func<Task>で使用する場合、引数が使用出来ない?ため変数を用意 6 7 /// <summary> 8 /// DragEventArgs 9 /// </summary> 10 private DragEventArgs Temp_e; 11 /// <summary> 12 /// ListView 13 /// </summary> 14 private ListView Temp_ListView; 15 /// <summary> 16 /// 拡張子判定用 17 /// </summary> 18 private string Temp_SelectExtension; 19 20 //----------------------------------------formイベント------------------------------------------ 21 22 private void listViewTextList_DragEnter(object sender, DragEventArgs e) 23 { 24 //ファイルドロップ操作受付 25 e.Effect = DragDropEffects.All; 26 } 27 28 private async void listViewTextList_DragDrop(object sender, DragEventArgs e) 29 { 30 //awaitは使用するが非同期になっていない。 31 await DropDataCheck(e, listViewTextList, ".txt"); 32 } 33 34 //----------------------------------------DragDropイベント------------------------------------------ 35 36 private async Task DropDataCheck(DragEventArgs e,ListView TempListView,string SelectExtension) 37 { 38 //Func<Task>で使用する場合、引数が使用出来ない?ため先に変数へ入れておく 39 Temp_e = e; 40 Temp_ListView = TempListView; 41 Temp_SelectExtension = SelectExtension; 42 43 //TextBoxに処理開始を記載させて動作確認 44 //DropDataCheckはawaitと記述しているがthis.InvokeRequiredはfalseであり、InvokeせずControlに触っても影響がない。 45 InvokeTextBox(richTextBoxResult,"処理を開始しました。"); 46 47 //await時に戻り値へawaitを記載すると書いてあるので検証用にTask<string>で戻している。 48 //※this.InvokeRequiredはfalseであり、InvokeせずControlに触っても影響がない。 49 var data = await DropDataCheckAsync(); 50 51 //下記2行を使用した場合は非同期処理になっている。 52 //※this.InvokeRequiredがTrueとなり、InvokeせずControlに触ればエラーになる。 53 Func<Task> AsyncJob = DropDataCheckAsync; 54 await Task.Run(AsyncJob); 55 } 56 /// <summary> 57 /// Drop 58 /// 「CS1998:この非同期メソッドにはawait演算子がないため、同期的に実行されます」 59 /// </summary> 60 /// <returns></returns> 61 62 private async Task DropDataCheck(DragEventArgs e,ListView TempListView,string SelectExtension) 63 { 64 //Func<Task>で使用する場合、引数が使用出来ない?ため先に変数へ入れておく 65 Temp_e = e; 66 Temp_ListView = TempListView; 67 Temp_SelectExtension = SelectExtension; 68 69 //TextBoxに処理開始を記載させて動作確認 70 //DropDataCheckはawaitと記述しているがthis.InvokeRequiredはfalseであり、InvokeせずControlに触っても影響がない。 71 InvokeTextBox(richTextBoxResult,"処理を開始しました。"); 72 73 //await時に戻り値へawaitを記載すると書いてあるので検証用にTask<string>で戻している。 74 //※this.InvokeRequiredはfalseであり、InvokeせずControlに触っても影響がない。 75 var data = await DropDataCheckAsync(); 76 77 //下記2行を使用した場合は非同期処理になっている。 78 //※this.InvokeRequiredがTrueとなり、InvokeせずControlに触ればエラーになる。 79 Func<Task> AsyncJob = DropDataCheckAsync; 80 await Task.Run(AsyncJob); 81 } 82 /// <summary> 83 /// Drop 84 /// </summary> 85 /// <returns></returns> 86 private async Task<string> DropDataCheckAsync() 87 { 88 //ドロップされたデータがファイルなら取得 89 if (Temp_e.Data.GetDataPresent(DataFormats.FileDrop)) 90 { 91 //ファイルデータのみ列挙 92 string[] DropData = (string[])Temp_e.Data.GetData(DataFormats.FileDrop, false); 93 //列挙先のリスト初期化※非同期確認 94 InvokeListViewClear(Temp_ListView); 95 foreach (var file in DropData) 96 { 97 //フォルダはフォルダで後々処理するので列挙しておく 98 if (Directory.Exists(file)) 99 { 100 InvokeListViewAdd(Temp_ListView,file); 101 } 102 //ファイルは拡張子を確認して必要なデータのみ取得 103 if (File.Exists(file)) 104 { 105 //拡張子の大文字小文字へ対応 106 if (0 == string.Compare(Path.GetExtension(file), Temp_SelectExtension, true)) 107 { 108 InvokeListViewAdd(Temp_ListView, file); 109 } 110 } 111 } 112 } 113 //TextBoxに処理開始を記載させて動作確認 114 InvokeTextBox(richTextBoxResult, "処理を開始しました。\r処理を終了しました。"); 115 116 //var data = await DropDataCheckAsync();の構文にするためだけのreturn 117 //await DropDataCheckAsync();でTaskのreturn;でも同期処理になっている。 118 return "test"; 119 } 120 //----------------------------------------Invokeイベント------------------------------------------ 121 122 public delegate void DelegateUpdateTextBox(RichTextBox SelectTextBox, string WriteData); 123 public delegate void DelegateListViewAdd(ListView SelectListView, string file); 124 public delegate void DelegateListViewClear(ListView SelectListView); 125 126 private void InvokeTextBox(RichTextBox SelectTextBox,string WriteData) 127 { 128 //非同期であればFormのControlを触るとエラーになるためInvokeRequiredで確認 129 if (this.InvokeRequired) 130 { 131 //非同期処理中であればInvokeでエラー回避 132 this.Invoke(new DelegateUpdateTextBox(this.InvokeTextBox), SelectTextBox, WriteData); 133 return; 134 } 135 //同期中ならエラーにならないのでそのまま変更 136 SelectTextBox.Text = WriteData; 137 } 138 private void InvokeListViewAdd(ListView SelectListView,string file) 139 { 140 //非同期であればFormのControlを触るとエラーになるためInvokeRequiredで確認 141 if (this.InvokeRequired) 142 { 143 //非同期処理中であればInvokeでエラー回避 144 this.Invoke(new DelegateListViewAdd(this.InvokeListViewAdd),SelectListView, file); 145 return; 146 } 147 //同期中ならエラーにならないのでそのまま変更 148 SelectListView.Items.Add(file); 149 SelectListView.Items[Temp_ListView.Items.Count - 1].SubItems.Add(Path.GetFullPath(file)); 150 } 151 private void InvokeListViewClear(ListView SelectListView) 152 { 153 //非同期であればFormのControlを触るとエラーになるためInvokeRequiredで確認 154 if (this.InvokeRequired) 155 { 156 //非同期処理中であればInvokeでエラー回避 157 this.Invoke(new DelegateListViewClear(this.InvokeListViewClear), SelectListView); 158 return; 159 } 160 //同期中ならエラーにならないのでそのまま変更 161 SelectListView.Items.Clear(); 162 } 163
私の記述が誤っていて正確に非同期処理となっていないのでしょうか。
それともForm独特の挙動なのでしょうか。
大量のファイルを取得した後に処理を行うため、非同期処理を使用したいのです。
回答2件
あなたの回答
tips
プレビュー