これは私が動作させようとしている単なるサンプルテストコードです。私は進行状況を報告するより良い方法があることを知っていますが、私はこのコードがなぜ機能していないのかを知りたいだけです。私はファイルを読み込んで進行状況を報告していますが、UIをフリーズし、タスク全体が完了するまで待ちます。WPFで並列タスクを実装する方法は?
private async void runtTasksButton_Click(object sender, RoutedEventArgs e)
{
List<Task> tasks = new List<Task>();
var t = Task.Factory.StartNew(() =>
{
FileStream fs = File.OpenRead(@"C:\Whatever.txt");
var totalLength = fs.Length;
this.Dispatcher.BeginInvoke(new Action(() =>
{
progressBar1.Maximum = totalLength;
}), null);
using (fs)
{
byte[] b = new byte[1024];
while (fs.Read(b, 0, b.Length) > 0)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
progressBar1.Value += 1024;
}), null);
};
}
});
tasks.Add(t);
await Task.WhenAll(tasks.ToArray());
}
編集:私は約BackgroundWorker
とasync/await
知っています。しかし、私はちょうどTPL
の深い理解を得るためにこのコードブロックを理解しようとしています。私はFileStream.ReadAsync()
メソッドを使用していた、そのように実行時にProgressBar
を更新することができました:
private void runtTasksButton_Click(object sender, RoutedEventArgs e)
{
progressTextBox.Text = "";
label1.Content = "Milliseconds: ";
progressBar1.Value = 0;
progressBar2.Value = 0;
var watch = Stopwatch.StartNew();
List<Task> tasks = new List<Task>();
var t1 = Task.Factory.StartNew(() => ReadFile(@"C:\BigFile1.txt", progressBar1));
var t2 = Task.Factory.StartNew(() => ReadFile(@"C:\BigFile2.txt", progressBar2));
tasks.Add(t1);
tasks.Add(t2);
Task.Factory.ContinueWhenAll(tasks.ToArray(),
result =>
{
var time = watch.ElapsedMilliseconds;
this.Dispatcher.BeginInvoke(new Action(() =>
label1.Content += time.ToString()));
});
}
private async Task ReadFile(string path, ProgressBar progressBar)
{
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.None, 8192, true);
var totalLength = fs.Length;
await this.Dispatcher.BeginInvoke(new Action(() =>
{
progressBar.Maximum = totalLength;
}));
using (fs)
{
byte[] b = new byte[8192];
while (await fs.ReadAsync(b, 0, b.Length) > 0)
{
await this.Dispatcher.BeginInvoke(new Action(() =>
{
progressBar.Value += 8192;
}));
};
}
}
しかし、今で制御が完了するまでにタスクを読み込むファイルを待たずにContinueWhenAll
に入ります。しかし、タスクは意図したとおりにそれぞれのプログレスバーを更新します。誰かが説明をすることができれば、それは高く評価されます。
ます。http: //www.wpf-tutorial.com/misc/multi-threading-with-the-backgroundworker/ – zaitsman
[WPFバックグラウンドワーカーを使用する方法](https://stackoverflow.com/questions/5483565/how-to)の可能な複製-use-wpf-background-worker) – zaitsman
'async/await'を正しく使用している場合は、タスクが完了すると、制御は元のスレッド(この場合はUIスレッド)に返されるため、通常、Dispatcher.BeginInvokeは必要ありません。ここで問題となるのは、別のCPUバウンドの 'Task'(' Task.Factory.StartNew')を作っていることです。これはワーカースレッドになる可能性が最も高いです。ファイル読み込みなどのI/Oバウンド操作でCPUバインドタスクを使用しないでください。最初の場所で操作の 'xxxAsync'バージョンを使用してください。 'Task.Run'やそれに相当する – MickyD