给出这段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));
}
它返回所有包含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上通常同步文件IO比异步快。
我试着写了更快的异步版本
"异步 "并不意味着 "更快"。它的意思是 "不阻塞调用线程"。异步代码会有额外的开销,所以一般来说是 较慢. 异步代码的好处不是速度,而是释放线程。只有当这些线程有其他工作要做时,这才是一个好处;例如,在服务器环境中,它们可以处理其他请求。
还有一个问题是,像 File.OpenText
实际上不允许异步访问,所以什么是 ReadLineAsync
实际上是在线程池上运行同步工作,然后进行异步处理。但即使你有一个正确的异步实现,也不会比同步读取文件快。