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

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

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

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

Windows Forms

Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。

非同期処理

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

解決済

Task.Runを使用せずにasync-awaitだけで非同期処理を実現できるのか

dsnmae
dsnmae

総合スコア5

C#

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

Windows Forms

Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。

非同期処理

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

2回答

1評価

0クリップ

798閲覧

投稿2022/06/09 00:44

編集2022/06/09 17:44

参考にしたサイトは下記になります。

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#

public Form1() { InitializeComponent(); } //Func<Task>で使用する場合、引数が使用出来ない?ため変数を用意 /// <summary> /// DragEventArgs /// </summary> private DragEventArgs Temp_e; /// <summary> /// ListView /// </summary> private ListView Temp_ListView; /// <summary> /// 拡張子判定用 /// </summary> private string Temp_SelectExtension; //----------------------------------------formイベント------------------------------------------ private void listViewTextList_DragEnter(object sender, DragEventArgs e) { //ファイルドロップ操作受付 e.Effect = DragDropEffects.All; } private async void listViewTextList_DragDrop(object sender, DragEventArgs e) { //awaitは使用するが非同期になっていない。 await DropDataCheck(e, listViewTextList, ".txt"); } //----------------------------------------DragDropイベント------------------------------------------ private async Task DropDataCheck(DragEventArgs e,ListView TempListView,string SelectExtension) { //Func<Task>で使用する場合、引数が使用出来ない?ため先に変数へ入れておく Temp_e = e; Temp_ListView = TempListView; Temp_SelectExtension = SelectExtension; //TextBoxに処理開始を記載させて動作確認 //DropDataCheckはawaitと記述しているがthis.InvokeRequiredはfalseであり、InvokeせずControlに触っても影響がない。 InvokeTextBox(richTextBoxResult,"処理を開始しました。"); //await時に戻り値へawaitを記載すると書いてあるので検証用にTask<string>で戻している。 //※this.InvokeRequiredはfalseであり、InvokeせずControlに触っても影響がない。 var data = await DropDataCheckAsync(); //下記2行を使用した場合は非同期処理になっている。 //※this.InvokeRequiredがTrueとなり、InvokeせずControlに触ればエラーになる。 Func<Task> AsyncJob = DropDataCheckAsync; await Task.Run(AsyncJob); } /// <summary> /// Drop /// 「CS1998:この非同期メソッドにはawait演算子がないため、同期的に実行されます」 /// </summary> /// <returns></returns> private async Task DropDataCheck(DragEventArgs e,ListView TempListView,string SelectExtension) { //Func<Task>で使用する場合、引数が使用出来ない?ため先に変数へ入れておく Temp_e = e; Temp_ListView = TempListView; Temp_SelectExtension = SelectExtension; //TextBoxに処理開始を記載させて動作確認 //DropDataCheckはawaitと記述しているがthis.InvokeRequiredはfalseであり、InvokeせずControlに触っても影響がない。 InvokeTextBox(richTextBoxResult,"処理を開始しました。"); //await時に戻り値へawaitを記載すると書いてあるので検証用にTask<string>で戻している。 //※this.InvokeRequiredはfalseであり、InvokeせずControlに触っても影響がない。 var data = await DropDataCheckAsync(); //下記2行を使用した場合は非同期処理になっている。 //※this.InvokeRequiredがTrueとなり、InvokeせずControlに触ればエラーになる。 Func<Task> AsyncJob = DropDataCheckAsync; await Task.Run(AsyncJob); } /// <summary> /// Drop /// </summary> /// <returns></returns> private async Task<string> DropDataCheckAsync() { //ドロップされたデータがファイルなら取得 if (Temp_e.Data.GetDataPresent(DataFormats.FileDrop)) { //ファイルデータのみ列挙 string[] DropData = (string[])Temp_e.Data.GetData(DataFormats.FileDrop, false); //列挙先のリスト初期化※非同期確認 InvokeListViewClear(Temp_ListView); foreach (var file in DropData) { //フォルダはフォルダで後々処理するので列挙しておく if (Directory.Exists(file)) { InvokeListViewAdd(Temp_ListView,file); } //ファイルは拡張子を確認して必要なデータのみ取得 if (File.Exists(file)) { //拡張子の大文字小文字へ対応 if (0 == string.Compare(Path.GetExtension(file), Temp_SelectExtension, true)) { InvokeListViewAdd(Temp_ListView, file); } } } } //TextBoxに処理開始を記載させて動作確認 InvokeTextBox(richTextBoxResult, "処理を開始しました。\r処理を終了しました。"); //var data = await DropDataCheckAsync();の構文にするためだけのreturn //await DropDataCheckAsync();でTaskのreturn;でも同期処理になっている。 return "test"; } //----------------------------------------Invokeイベント------------------------------------------ public delegate void DelegateUpdateTextBox(RichTextBox SelectTextBox, string WriteData); public delegate void DelegateListViewAdd(ListView SelectListView, string file); public delegate void DelegateListViewClear(ListView SelectListView); private void InvokeTextBox(RichTextBox SelectTextBox,string WriteData) { //非同期であればFormのControlを触るとエラーになるためInvokeRequiredで確認 if (this.InvokeRequired) { //非同期処理中であればInvokeでエラー回避 this.Invoke(new DelegateUpdateTextBox(this.InvokeTextBox), SelectTextBox, WriteData); return; } //同期中ならエラーにならないのでそのまま変更 SelectTextBox.Text = WriteData; } private void InvokeListViewAdd(ListView SelectListView,string file) { //非同期であればFormのControlを触るとエラーになるためInvokeRequiredで確認 if (this.InvokeRequired) { //非同期処理中であればInvokeでエラー回避 this.Invoke(new DelegateListViewAdd(this.InvokeListViewAdd),SelectListView, file); return; } //同期中ならエラーにならないのでそのまま変更 SelectListView.Items.Add(file); SelectListView.Items[Temp_ListView.Items.Count - 1].SubItems.Add(Path.GetFullPath(file)); } private void InvokeListViewClear(ListView SelectListView) { //非同期であればFormのControlを触るとエラーになるためInvokeRequiredで確認 if (this.InvokeRequired) { //非同期処理中であればInvokeでエラー回避 this.Invoke(new DelegateListViewClear(this.InvokeListViewClear), SelectListView); return; } //同期中ならエラーにならないのでそのまま変更 SelectListView.Items.Clear(); }

私の記述が誤っていて正確に非同期処理となっていないのでしょうか。
それともForm独特の挙動なのでしょうか。
大量のファイルを取得した後に処理を行うため、非同期処理を使用したいのです。

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

dodox86

2022/06/09 07:15

大したことではないのですけど、タグに付けている"Google Cloud Platform"は関係無いので、外すことをお勧めします。
dsnmae

2022/06/09 08:02

WindowsFormを選択したつもりでしたが誤ってForm違いで選んでいました。 修正しました。

まだ回答がついていません

会員登録して回答してみよう

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

ただいまの回答率
87.20%

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

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

質問する

関連した質問

同じタグがついた質問を見る

C#

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

Windows Forms

Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。

非同期処理

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