并行 forEach 搜索文件
Parallel forEach search file
我有一个包含2个列表框的程序,这个程序是基于搜索文件,然后与StopWatch
比较使用AsyncAwait
和TPL的区别...第一个列表框做使用 AsyncAwait
的函数(我不知道这是否是更好的方法,但它有效,请参阅下面的代码)
private async void button1_Click(object sender, EventArgs e)
{
Stopwatch stopWatch = new Stopwatch();
foreach (string d in Directory.GetDirectories(@"C:\Visual Studio Projectes\Hash\AsyncAwait\Carpetes"))
{
foreach (string s in Directory.GetFiles(d))
{
stopWatch.Start();
listBox1.Items.Add(s);
await Task.Delay(1);
btIniciar1.Enabled = false;
}
}
btIniciar1.Enabled = true;
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
textBox1.Text = ts.ToString("mm\:ss\.ff") + (" minuts");
}
然后在我的第二个列表框中我卡住了,我不知道如何实现 Parallel.ForEach
来表现得像 async
,更好的方法是什么?我找不到在这种情况下使用 TPL 来执行与我的第一个列表框相同的方法,你能帮我吗?
在您的示例代码中使用 async
毫无意义,因为它实际上并没有异步执行任何操作。如果要将同步代码包装在后台线程中,请使用 Task.Run
.
关于Parallel.ForEach
,您可以通过将其包装在Task.Run
中来异步处理它:await Task.Run(() => Parallel.ForEach(...));
注意 parallel/background 个线程不能直接访问 UI 个元素。如果您想从 background/threadpool 线程更新 UI,您可以使用 IProgress<T>
/Progress<T>
。
更新:
序列号如下:
private async void button1_Click(object sender, EventArgs e)
{
IProgress<string> progress = new Progress<string>(update =>
{
listBox1.Items.Add(s);
btIniciar1.Enabled = false;
});
var ts = await Task.Run(() =>
{
Stopwatch stopWatch = new Stopwatch();
foreach (string d in Directory.GetDirectories(@"C:\Visual Studio Projectes\Hash\AsyncAwait\Carpetes"))
{
foreach (string s in Directory.GetFiles(d))
{
stopWatch.Start();
progress.Report(s);
}
}
stopWatch.Stop();
return stopWatch.Elapsed;
});
btIniciar1.Enabled = true;
textBox1.Text = ts.ToString("mm\:ss\.ff") + (" minuts");
}
并行代码如下所示:
private async void button1_Click(object sender, EventArgs e)
{
IProgress<string> progress = new Progress<string>(update =>
{
listBox1.Items.Add(s);
btIniciar1.Enabled = false;
});
var ts = await Task.Run(() => Parallel.ForEach( ...
));
btIniciar1.Enabled = true;
textBox1.Text = ts.ToString("mm\:ss\.ff") + (" minuts");
}
我终于解决了这个问题:
DirectoryInfo nodeDir = new DirectoryInfo(@"c:\files");
Parallel.ForEach(nodeDir.GetDirectories(), async dir =>
{
foreach (string s in Directory.GetFiles(dir.FullName))
{
Invoke(new MethodInvoker(delegate { lbxParallel.Items.Add(s); }));
contador++;
await Task.Delay(1);
}
}
我有一个包含2个列表框的程序,这个程序是基于搜索文件,然后与StopWatch
比较使用AsyncAwait
和TPL的区别...第一个列表框做使用 AsyncAwait
的函数(我不知道这是否是更好的方法,但它有效,请参阅下面的代码)
private async void button1_Click(object sender, EventArgs e)
{
Stopwatch stopWatch = new Stopwatch();
foreach (string d in Directory.GetDirectories(@"C:\Visual Studio Projectes\Hash\AsyncAwait\Carpetes"))
{
foreach (string s in Directory.GetFiles(d))
{
stopWatch.Start();
listBox1.Items.Add(s);
await Task.Delay(1);
btIniciar1.Enabled = false;
}
}
btIniciar1.Enabled = true;
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
textBox1.Text = ts.ToString("mm\:ss\.ff") + (" minuts");
}
然后在我的第二个列表框中我卡住了,我不知道如何实现 Parallel.ForEach
来表现得像 async
,更好的方法是什么?我找不到在这种情况下使用 TPL 来执行与我的第一个列表框相同的方法,你能帮我吗?
在您的示例代码中使用 async
毫无意义,因为它实际上并没有异步执行任何操作。如果要将同步代码包装在后台线程中,请使用 Task.Run
.
关于Parallel.ForEach
,您可以通过将其包装在Task.Run
中来异步处理它:await Task.Run(() => Parallel.ForEach(...));
注意 parallel/background 个线程不能直接访问 UI 个元素。如果您想从 background/threadpool 线程更新 UI,您可以使用 IProgress<T>
/Progress<T>
。
更新:
序列号如下:
private async void button1_Click(object sender, EventArgs e)
{
IProgress<string> progress = new Progress<string>(update =>
{
listBox1.Items.Add(s);
btIniciar1.Enabled = false;
});
var ts = await Task.Run(() =>
{
Stopwatch stopWatch = new Stopwatch();
foreach (string d in Directory.GetDirectories(@"C:\Visual Studio Projectes\Hash\AsyncAwait\Carpetes"))
{
foreach (string s in Directory.GetFiles(d))
{
stopWatch.Start();
progress.Report(s);
}
}
stopWatch.Stop();
return stopWatch.Elapsed;
});
btIniciar1.Enabled = true;
textBox1.Text = ts.ToString("mm\:ss\.ff") + (" minuts");
}
并行代码如下所示:
private async void button1_Click(object sender, EventArgs e)
{
IProgress<string> progress = new Progress<string>(update =>
{
listBox1.Items.Add(s);
btIniciar1.Enabled = false;
});
var ts = await Task.Run(() => Parallel.ForEach( ...
));
btIniciar1.Enabled = true;
textBox1.Text = ts.ToString("mm\:ss\.ff") + (" minuts");
}
我终于解决了这个问题:
DirectoryInfo nodeDir = new DirectoryInfo(@"c:\files");
Parallel.ForEach(nodeDir.GetDirectories(), async dir =>
{
foreach (string s in Directory.GetFiles(dir.FullName))
{
Invoke(new MethodInvoker(delegate { lbxParallel.Items.Add(s); }));
contador++;
await Task.Delay(1);
}
}