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

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

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

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

並列処理

複数の計算が同時に実行される手法

非同期処理

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

Q&A

解決済

2回答

1097閲覧

Taskを使った非同期処理で処理が終わった順番に番号を振り表示する方法が知りたい。

退会済みユーザー

退会済みユーザー

総合スコア0

C#

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

並列処理

複数の計算が同時に実行される手法

非同期処理

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

0グッド

0クリップ

投稿2021/04/02 11:37

提示子ですがマルチタスクで音楽ファイルをエンコードしてするのですが終わった順番から[ 2 / 300] : タイトル 
のように画面に表示させたいのですがどうすればいいのでしょうか?
Task.Runに数字を入れましたが非同期ですので数字がバラバラで順番になりません。これはどうしたらいいのでしょうか?

cs

1using System; 2using System.Threading.Tasks; 3using System.Diagnostics; 4using System.IO; 5using System.Collections.Generic; 6 7namespace Test 8{ 9 class Program 10 { 11 //ダブルクォートをつける 12 static string AddDoubleQuote(string path) 13 { 14 return "\"" + path + "\""; 15 } 16 17 //ダブルクォートを外す 18 static string DeleteDoubleQuote(string path) 19 { 20 path = path.Replace("\"", ""); 21 path = path.Replace("\"", ""); 22 23 return path; 24 } 25 26 27 //ディレクトリ内部を表示 28 static List<string> GetDirectory(string path) 29 { 30 List<string> name = new List<string>(); 31 string[] list = Directory.GetFiles(path, "*", SearchOption.AllDirectories); 32 33 foreach (string na in list) 34 { 35 name.Add(na); 36 } 37 38 return name; 39 } 40 41 //コマンドを取得 42 static string GetCommand(string in_path,string out_path) 43 { 44 in_path = "\"" + in_path + "\""; 45 46 string ext = Path.GetExtension(in_path); 47 ext = ext.Replace("\"", ""); 48 //Console.WriteLine(ext); 49 if (ext == ".flac") 50 { 51// Console.WriteLine("ああああ " + ext ); 52 out_path = "\""+ out_path.Replace(ext, ".m4a"); 53 54 55 string command = " -i " + in_path + " -c:v copy -metadata comment=\"\" -acodec alac" + " " + out_path + "\""; 56 return command; 57 } 58 else 59 { 60 return null; 61 } 62 63 } 64 //////////////////////////////////////////////////////////////////////////////////////////////////// 65 //ファイルをエンコードする 66 public static async Task<int> ConvertFile(string in_path,string out_path) 67 { 68 return await Task.Run(() => 69 { 70 Process pro = new Process(); 71 72 //エンコードをかける 73 string st = GetCommand(in_path,out_path); 74 if (st != null) 75 { 76 77 pro.StartInfo.FileName = "ffmpeg.exe"; 78 pro.StartInfo.Arguments = st; //引数 79 pro.StartInfo.CreateNoWindow = true; //コンソール画面を表示しない。 80 pro.Start(); 81 pro.WaitForExit(); //処理を待機 82 //Console.WriteLine("exit code: " + pro.ExitCode); 83 Console.WriteLine(Path.GetFileName(st)); 84 85 int e = pro.ExitCode; 86 pro.Close(); 87 88 return e; 89 //return pro.ExitCode; 90 } 91 else 92 { 93 // Console.WriteLine("Error"); 94 return -1; 95 } 96 }); 97 98 } 99////////////////////////////////////////////////////////////////////////////////////////////////////////////// 100 101 102 103 104 static void Main(string[] args) 105 { 106 107 //string str = args[0]; 108 string str = Console.ReadLine(); //ファイル名をD&D 109 str = DeleteDoubleQuote(str); //ダブルクォートを外す 110 111 List<string> filePath = GetDirectory(str); //ディレクトリを取得 112 List<string> destPath = new List<string>(); //保存先のパス 113 List<Task<int>> tasklist = new List<Task<int>>(); //タスクリスト 114 115 int num = 0; 116 foreach (string n in filePath) 117 { 118 Directory.CreateDirectory(Path.GetDirectoryName(n.Replace(Directory.GetParent(str).FullName, Directory.GetCurrentDirectory()))); //フォルダ作成 119 tasklist.Add(ConvertFile(n, n.Replace(Directory.GetParent(str).FullName, Directory.GetCurrentDirectory()))); 120 } 121 122 Task.WaitAll(tasklist.ToArray()); //待機 123 124 125 Console.WriteLine("変換終了"); 126 127 Console.ReadKey(); 128 } 129 } 130} 131

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2021/04/02 13:25

そもそも何故非同期で実行したいのでしょう? CPUをフルに使いたいだけなら、ffmpeg自体をマルチスレッドで起動すれば良さそうですが。
退会済みユーザー

退会済みユーザー

2021/04/02 14:24 編集

質問ですがその場合Task処理は外さないといけないのでしょうか?
退会済みユーザー

退会済みユーザー

2021/04/02 14:31

別に使ってもいいですけど、特にメリットはないと思います。(むしろ非同期で処理がややこしくなるのがデメリット)
guest

回答2

0

無理だと思います。どうしても終わった順番を付けたいということなら、非同期をやめて同期に処理する他なさそうです。

投稿2021/04/02 12:07

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

dodox86

2021/04/02 12:53

全体として非同期ではあっても、Lock系のオブジェクトを使うことでほぼ、終わった順に同期的に採番することはできると思いますが、これまでの当質問者さんの問題への向き合い方からすると、残念ながら無理と思える難易度だとは思います。
guest

0

ベストアンサー

単純にインクリメントするだけだとダメだったので、Interlocked.Increment メソッドはどうかな?ってやってみたんですが、ダメなんですかね?

C#

1using System; 2using System.Collections.Generic; 3using System.Threading.Tasks; 4using System.Threading; 5 6namespace TeraTaskFinishNum { 7 class Program { 8 public static async Task<int> ConvertFile(string in_path, string out_path) { 9 return await Task.Run(() => { 10 var r = new Random(); 11 var t = r.Next(500, 1000); 12 System.Threading.Thread.Sleep(t); 13 Console.WriteLine("[" + (Interlocked.Increment(ref num)) + "/" + max + "] " + in_path + " " + out_path + " " + t); 14 return 1; 15 }); 16 17 } 18 static int num = 0; 19 static int max = 0; 20 static void Main(string[] args) { 21 num = 0; 22 max = 300; 23 List<Task<int>> tasklist = new List<Task<int>>(); 24 for (int i = 0; i < max; i++) { 25 tasklist.Add(ConvertFile("aaa"+i, "bbb")); 26 } 27 Task.WaitAll(tasklist.ToArray()); 28 Console.Read(); 29 } 30 } 31}

ご指摘いただいた通りデッドロックしたため、Windowsフォーム版の例を追記しておきます。

C#

1using System; 2using System.Collections.Generic; 3using System.ComponentModel; 4using System.Data; 5using System.Drawing; 6using System.Linq; 7using System.Text; 8using System.Threading; 9using System.Threading.Tasks; 10using System.Windows.Forms; 11 12namespace MultiTaskIncrement { 13 public partial class Form1 : Form { 14 public Form1() { 15 InitializeComponent(); 16 } 17 18 int num = 0; 19 int max = 0; 20 public async Task<int> ConvertFile(string in_path, string out_path) { 21 return await Task.Run(() => { 22 var r = new Random(); 23 var t = r.Next(500, 1000); 24 System.Threading.Thread.Sleep(t); 25 this.Invoke((MethodInvoker)delegate() { 26 listBox1.Items.Add("[" + (Interlocked.Increment(ref num)) + "/" + max + "] " + in_path + " " + out_path + " " + t); 27 }); 28 return 1; 29 }); 30 } 31 32 private async void button1_Click(object sender, EventArgs e) { 33 num = 0; 34 max = 300; 35 List<Task<int>> tasklist = new List<Task<int>>(); 36 for (int i = 0; i < max; i++) { 37 tasklist.Add(ConvertFile("aaa" + i, "bbb")); 38 } 39 await Task.Run(() => { 40 Task.WaitAll(tasklist.ToArray()); 41 }); 42 MessageBox.Show("owari"); 43 } 44 } 45} 46

投稿2021/04/02 13:51

編集2021/04/03 04:01
Hey_CH

総合スコア437

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

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

Hey_CH

2021/04/02 13:52

って、もうベストアンサーついてました。すいません。
退会済みユーザー

退会済みユーザー

2021/04/02 14:23

自分もその後知り合いに聞いてそのやり方見つけました。
退会済みユーザー

退会済みユーザー

2021/04/03 01:42 編集

そのコードは WinForms とか WPF などの GUI アプリではたぶんデッドロックになると思いますのでご注意を。回答のコードはコンソールアプリですのでデッドロックにならなかったということだと理解しています。(プラス評価を付けた手前注意を書かせていただきました)
Hey_CH

2021/04/03 02:08

なるほど、コンソールアプリだからたまたまうまく動いてるって事なんですね。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問