【问题标题】:Is valid return "Task<Task<MyObject>>" ? Or is better return "Task.FromResult(MyObject)"是否有效返回 "Task<Task<MyObject>>" ?或者更好地返回“Task.FromResult(MyObject)”
【发布时间】:2019-04-03 03:02:10
【问题描述】:

我的代码没问题,但我想知道哪种风格更好,你会怎么看,我在玩异步方法。

让我建立上下文:

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());
    }

【问题讨论】:

  • 你应该解释你正在努力实现的目标,而不是你不理解的事情中哪个更好。
  • 如果你写了ReadAnimalXML2()你需要改变它。 imo,它应该是public Animal ReadAnimalXML2return new Animal(),但如果它必须是异步的,那么public Task&lt;Animal&gt; ReadAnimalXML2return Task.FromResult(new Animal())。如果没有显示 await 语句,则改为 public async Task&lt;Animal&gt; ReadAnimalXML2return new Animal()
  • MMMM,这两种方法都是正确的,但是这些方法中哪些是“更正确”的。在现实生活中的代码中你们使用 Task> ?
  • 我不明白你想要达到什么目的。你想实现并行还是异步?或两者?如果您没有实现它们,我不会感到惊讶,并且您的代码的核心是在 UI 线程上同步运行。

标签: c# asynchronous async-await


【解决方案1】:

我认为您将并行性与异步性混为一谈,并且两者都做对了。

如果您的方法返回Task.FromResult,那么它不是异步的。如果您想要异步代码,请关注 I/O - 例如,异步执行 I/O 以从磁盘加载文件数据,然后(同步)将其解析为 XML。

Parallel.ForEach 问题更危险。首先,您不能将async 方法与Parallel.ForEach 一起使用;您的代码恰好可以工作,因为您的 async 方法不是异步的。此外,您不能在并行代码中使用非线程安全方法,例如 List&lt;T&gt;.Add。所以几乎所有使用Parallel.ForEach 的代码都是错误的。但你可能不需要Parallel.ForEach

如果你想做异步并发,那么你只需要LINQ的Selectawait Task.WhenAll。如果你想建立一种可以做并行处理的管道,那么你可以使用TPL Dataflow,或者在异步部分完成后使用Parallel.ForEachonly同步代码。

【讨论】:

  • 非常好的回答先生!我会接受这个建议
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-05
  • 2012-09-10
  • 2011-12-24
  • 1970-01-01
  • 2018-10-13
  • 2018-11-27
相关资源
最近更新 更多