我的代码还可以,但是我想知道哪种风格更好,如何看待,我正在使用异步方法。
让我建立上下文:
Parallel.ForEach(xmlAnimalList, async xml =>
{
taskList.Add(await Task.FromResult(ReadAnimalXML(xml, token)));
});
此代码段可通过此方法很好地工作:
public async Task<Animal> ReadAnimalXML(string filename, CancellationToken token)
在前面的示例中,您可以在await关键字之后看到 Task.FromResult()。 ReadAnimalXML方法仅返回:
return new Animal();
第二个示例是:
Parallel.ForEach(xmlAnimalList, async xml =>
{
taskList.Add(await ReadAnimalXML2(xml, token));
});
这次,ReadAnimalXML2方法返回以下内容:
public async Task<Task<Animal>> ReadAnimalXML2(string filename, CancellationToken token)
{
return Task.FromResult(new Animal());
}
但是!
第二种方法ReadAnimalXML2(对我来说似乎很奇怪)返回一个
Task<Task<Animal>>
任务内部的任务。
这就是为什么我返回 Task.FromResult(new Animal()); 的原因 否则它将无法正常工作。两种方法都可以,但是更好。您能否分享您的答案,并解释原因?
谢谢您输入此问题。 编码很有趣!
public async Task<IEnumerable<Animal>> ReadXMLFromFolderAsync(string folderPath, CancellationToken token)
{
if (!Directory.Exists(folderPath))
{
return new List<Animal>();
}
List<Task<Animal>> taskList = new List<Task<Animal>>();
List<string> xmlAnimalList = Directory.GetFiles(folderPath, "*.xml").ToList();
Parallel.ForEach(xmlAnimalList, async xml =>
{
taskList.Add(await Task.FromResult(ReadAnimalXML(xml, token)));
});
return await Task.WhenAll(taskList);
}
public async Task<Animal> ReadAnimalXML(string filename, CancellationToken token)
{
XDocument document = XDocument.Load(filename);
IEnumerable<XElement> ADN = await Task.Run(() =>
document.Descendants("ADN").Where(adn => adn.Name.LocalName == "Dinosaur"), token);
//populate the animal object
return new Animal();
}
public async Task<IEnumerable<Animal>> ReadXMLFromFolderAsync2(string folderPath, CancellationToken token)
{
if (!Directory.Exists(folderPath))
{
return new List<Animal>();
}
List<Task<Animal>> taskList = new List<Task<Animal>>();
List<string> xmlAnimalList = Directory.GetFiles(folderPath, "*.xml").ToList();
Parallel.ForEach(xmlAnimalList, async xml =>
{
taskList.Add(await ReadAnimalXML2(xml, token));
});
return await Task.WhenAll(taskList);
}
public async Task<Task<Animal>> ReadAnimalXML2(string filename, CancellationToken token)
{
XDocument document = XDocument.Load(filename);
IEnumerable<XElement> ADN = await Task.Run(() => document
.Descendants("ADN")
.Where(adn => adn
.Name
.LocalName == "Dinosaur")
, token);
//populate the animal object
return Task.FromResult(new Animal());
}
答案 0 :(得分:5)
我认为您正在将并行性与异步性混淆,并且两者都不正确。
如果您的方法返回Task.FromResult
,则它不是异步的。如果要使用异步代码,请专注于I / O,例如,异步执行I / O以从磁盘加载文件数据,然后(同步)将其解析为XML。
Parallel.ForEach
问题更加危险。首先,不能将async
方法与Parallel.ForEach
一起使用;您的代码恰好起作用,因为您的async
方法不是异步的。另外,您不能在并行代码中使用非线程安全方法,例如List<T>.Add
。因此,几乎所有使用Parallel.ForEach
的代码都是错误的。但是您可能仍然不需要Parallel.ForEach
。
如果要进行异步并发,则只需要LINQ的Select
和await Task.WhenAll
。如果要建立一种可以并行处理的管道,那么在完成异步部分之后,可以使用TPL Dataflow,也可以对同步代码使用Parallel.ForEach
仅。 / p>