Dies ist nur Beispiel Testcode, den ich versuche zu arbeiten. Ich weiß, dass es bessere Möglichkeiten gibt, Fortschritte zu melden, aber ich möchte nur wissen, warum dieser Code nicht funktioniert. Ich lese eine Datei und berichte über den Fortschritt, aber sie friert die Benutzeroberfläche ein und wartet, bis die gesamte Aufgabe erledigt ist.Wie Implementieren paralleler Task in 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());
}
EDIT: Ich weiß über BackgroundWorker
und async/await
. Aber ich versuche nur, diesen Block Code herauszufinden, um ein tieferes Verständnis der TPL
zu bekommen. Ich habe die FileStream.ReadAsync()
Methode und konnte die ProgressBar
zur Laufzeit als solche aktualisieren:
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;
}));
};
}
}
Doch jetzt geht die Steuerung in den ContinueWhenAll
ohne die Datei zu warten Aufgaben Lesen abzuschließen. Die Tasks aktualisieren jedoch die entsprechenden ProgressBars wie vorgesehen. Wenn jemand einige Erklärungen geben könnte, würde das geschätzt werden.
http: //www.wpf-tutorial.com/misc/multi-threading-with-the-backgroundworker/ – zaitsman
Mögliches Duplikat von [Wie verwende ich WPF Background Worker] (https://stackoverflow.com/questions/5483565/how-to -use-wpf-background-worker) – zaitsman
Wenn Sie 'async/await' verwenden, ist dies korrekt e ist im Allgemeinen nicht erforderlich für "Dispatcher.BeginInvoke", da nach Abschluss der Task die Steuerung an den ursprünglichen Thread zurückgegeben wird, in diesem Fall an den UI-Thread. Das Problem hier ist, dass Sie eine andere CPU-gebundene 'Task' (' Task.Factory.StartNew') erstellen, die höchstwahrscheinlich ein Worker-Thread sein wird. Verwenden Sie keine CPU-gebundenen Aufgaben mit E/A-gebundenen Operationen, z. B. Lesen einer Datei. Verwenden Sie an erster Stelle die 'xxxAsync'-Versionen der Operationen. Keine Notwendigkeit für "Task.Run" oder gleichwertige – MickyD