.NET PLINQ 与异步性能
.NET PLINQ vs Async Performance
鉴于此 PLINQ 代码:
public static IEnumerable<Tuple<string, string>> PlinqFileProcessingLimitedCores(int nr_of_cores)
{
string archiveDirectory = @"C:\Dotnet46Examples";
return (from file in Directory.EnumerateFiles(archiveDirectory, "*.cs", SearchOption.AllDirectories)
from line in File.ReadLines(file).AsParallel().WithDegreeOfParallelism(nr_of_cores)
where line.Contains("Console")
select new Tuple<string, string>(file, line));
}
其中 returns 所有文件的所有行都包含单词 Console。
我尝试编写更快的异步版本,但是它们都比 PLINQ 慢得多,例如:
public static async Task<ConcurrentBag<Tuple<string, string>>> FileProcessingAsync()
{
string archiveDirectory = @"C:\Dotnet46Examples";
var bag = new ConcurrentBag<Tuple<string, string>>();
var tasks = Directory.EnumerateFiles(archiveDirectory, "*.cs", SearchOption.AllDirectories)
.Select(file => ProcessFileAsync(bag, file));
await Task.WhenAll(tasks);
return bag;
}
static async Task ProcessFileAsync(ConcurrentBag<Tuple<string, string>> bag, string file)
{
String line;
using (StreamReader reader = File.OpenText(file))
{
while (reader.Peek() >= 0)
{
line = await reader.ReadLineAsync();
if (line != null)
{
if (line.Contains("Console"))
{
bag.Add(new Tuple<string, string>(file, line));
}
}
}
}
}
为什么异步代码这么慢(在我的笔记本电脑上慢了 1000 倍)?
更好的代码是什么样子的?
这个问题不适合异步吗?
谢谢
您的并行示例是(同步)一次一行将文件读入内存并(并行)搜索文本。这可能是可用的最快解决方案,因为 Windows 上的同步文件 I/O 通常比异步文件快。
I tried to write faster asynch versions
"Asynchronous" 并不代表 "faster"。意思是"does not block the calling thread"。异步代码有额外的开销,因此通常 较慢 。异步代码的好处不是速度,而是速度。它正在释放线程。只有当这些线程有其他工作要做时,这才有好处;例如,在服务器环境中,他们可以处理其他请求。
还有一个问题是 File.OpenText
这样的方法实际上不允许异步访问,所以 ReadLineAsync
实际上做的是 运行 在线程池上同步工作然后异步处理它。但是即使你有一个正确的异步实现,它也不会比同步读取文件更快。
鉴于此 PLINQ 代码:
public static IEnumerable<Tuple<string, string>> PlinqFileProcessingLimitedCores(int nr_of_cores)
{
string archiveDirectory = @"C:\Dotnet46Examples";
return (from file in Directory.EnumerateFiles(archiveDirectory, "*.cs", SearchOption.AllDirectories)
from line in File.ReadLines(file).AsParallel().WithDegreeOfParallelism(nr_of_cores)
where line.Contains("Console")
select new Tuple<string, string>(file, line));
}
其中 returns 所有文件的所有行都包含单词 Console。
我尝试编写更快的异步版本,但是它们都比 PLINQ 慢得多,例如:
public static async Task<ConcurrentBag<Tuple<string, string>>> FileProcessingAsync()
{
string archiveDirectory = @"C:\Dotnet46Examples";
var bag = new ConcurrentBag<Tuple<string, string>>();
var tasks = Directory.EnumerateFiles(archiveDirectory, "*.cs", SearchOption.AllDirectories)
.Select(file => ProcessFileAsync(bag, file));
await Task.WhenAll(tasks);
return bag;
}
static async Task ProcessFileAsync(ConcurrentBag<Tuple<string, string>> bag, string file)
{
String line;
using (StreamReader reader = File.OpenText(file))
{
while (reader.Peek() >= 0)
{
line = await reader.ReadLineAsync();
if (line != null)
{
if (line.Contains("Console"))
{
bag.Add(new Tuple<string, string>(file, line));
}
}
}
}
}
为什么异步代码这么慢(在我的笔记本电脑上慢了 1000 倍)? 更好的代码是什么样子的? 这个问题不适合异步吗? 谢谢
您的并行示例是(同步)一次一行将文件读入内存并(并行)搜索文本。这可能是可用的最快解决方案,因为 Windows 上的同步文件 I/O 通常比异步文件快。
I tried to write faster asynch versions
"Asynchronous" 并不代表 "faster"。意思是"does not block the calling thread"。异步代码有额外的开销,因此通常 较慢 。异步代码的好处不是速度,而是速度。它正在释放线程。只有当这些线程有其他工作要做时,这才有好处;例如,在服务器环境中,他们可以处理其他请求。
还有一个问题是 File.OpenText
这样的方法实际上不允许异步访问,所以 ReadLineAsync
实际上做的是 运行 在线程池上同步工作然后异步处理它。但是即使你有一个正确的异步实现,它也不会比同步读取文件更快。