I have following code in WPF, my problems are :
txtResult1.text
, txtResult2.text
, txtResult3.text
inside worker_DoWork
events. But how to fix this ?ReadLineAsync
and WriteLineAsync
for code ?Here is my code:
public MainWindow()
{
InitializeComponent();
}
private readonly BackgroundWorker worker = new BackgroundWorker();
private void btnStart_Click(object sender, RoutedEventArgs e)
{
worker.DoWork +=worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.WorkerReportsProgress = true;
worker.RunWorkerAsync();
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Done");
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
Parallel.Invoke(() =>
{ Task.Run(() => txtResult1.text = ReadCharacter("C:\\File 1.txt")); },
() =>
{ Task.Run(() => txtResult2.text = ReadCharacter("C:\\File 2.txt")); },
() =>
{ Task.Run(() => txtResult3.text = ReadCharacter("C:\\File 3.txt")); }
);
}
private string ReadCharacter(string inputFile)
{
string result; string TID;
using (StreamReader sr =new StreamReader(inputFile))
using (StreamWriter sw = new StreamWriter(string.Format("{0}--Out.txt", inputFile.Replace(".txt",""))))
{
var sb = new StringBuilder();
TID = "Thread ID: "+ Thread.CurrentThread.ManagedThreadId.ToString();
sb.AppendLine(TID);
sb.AppendLine("T Start : " + DateTime.Now.ToLongTimeString() + "." +
DateTime.Now.Millisecond).ToString();
while (!sr.EndOfStream)
{
result = sr.ReadLine();
sw.WriteLine(result);
};
return
sb.AppendLine("T Stop : "+DateTime.Now.ToLongTimeString() + "." +
DateTime.Now.Millisecond).ToString();
}
}
There are several problems with your approach:
Task.Run
doesn't buy you anything if you're already using Parallel.Invoke
.Parallel
is the wrong solution if you want to do concurrent I/O - Parallel
is for parallel CPU-bound operations.BackgroundWorker
is pretty much legacy at this point. I have a blog series that shows how Task.Run
is better than BackgroundWorker
.Also, as @HansPassnat pointed out, you almost certainly do not want concurrent disk access since that will usually slow you down considerably.
But if you really want to do it, I'd recommend an async
approach:
private async void btnStart_Click(object sender, RoutedEventArgs e)
{
var progress = new Progress<string>(value => { txtResult1.Text = value; });
await Task.WhenAll(ReadCharacterAsync("C:\\File 1.txt", progress),
ReadCharacterAsync("C:\\File 2.txt", progress),
ReadCharacterAsync("C:\\File 3.txt", progress));
MessageBox.Show("Done");
}
private async Task ReadCharacterAsync(string inputFile, IProgress<string> progress)
{
string result; string TID;
using (var inFile = new FileStream(inputFile, FileMode.Open, FileAccess.Read, FileShare.None, 8192, useAsync: true))
using (var outFile = new FileStream(string.Format("{0}--Out.txt", inputFile.Replace(".txt","")), FileMode.Create, FileAccess.ReadWrite, FileShare.None, 8192, useAsync: true))
using (StreamReader sr =new StreamReader(inFile))
using (StreamWriter sw = new StreamWriter(outFile))
{
var sb = new StringBuilder();
TID = "Thread ID: "+ Thread.CurrentThread.ManagedThreadId.ToString();
sb.AppendLine(TID);
sb.AppendLine("T Start : " + DateTime.Now.ToLongTimeString() + "." +
DateTime.Now.Millisecond).ToString();
while (!sr.EndOfStream)
{
result = await sr.ReadLineAsync();
await sw.WriteLineAsync(result);
};
progress.Report(
sb.AppendLine("T Stop : "+DateTime.Now.ToLongTimeString() + "." +
DateTime.Now.Millisecond).ToString());
}
}