【问题标题】:Async tasks inside of task任务内的异步任务
【发布时间】:2022-02-15 23:39:24
【问题描述】:

我将数百个 xml 文件加载到两个不同的数据表中,以便在网格中绑定和显示每个数据表。这是针对 Windows 窗体应用程序的。

每个查询都与另一个非常不同,因此运行一个查询并加载两个表是行不通的。

我正在使用它来加载 xml:

    public async Task loadXMLs(List<string> xmlfiles)
    {

        var loadTasks = new List<Task>();

        foreach (String xml in xmlfiles)
        {
            loadTasks.Add(Task.Run(() => openXMLs(xml)));
        }            

        await Task.WhenAll(loadTasks);
        
    }
    
    public static async Task openXMLs(string xml)
    {           
        XDocument xdoc = XDocument.Load(xml);;

        if(xdoc != null)
        {
            loadXMLdatatable1(xdoc, xml);
            loadXMLdatatable2(xdoc, xml);               
        }
    }
    
    public static async Task loadXMLdatatable1(XDocument xdoc, string xml)
    {
        var query = xdoc.Elements (Long query here for XML)
        
        lock(datatable1)
        {
            foreach(var item in query)
            {
                datatable1.Rows.Add(
                    item
                );
            }
        }           
    }
    
    public static async Task loadXMLdatatable2(XDocument xdoc, string xml)
    {
        var query = xdoc.Elements (Long query here for XML)
        
        lock(datatable2)
        {
            foreach(var item in query)
            {
                datatable2.Rows.Add(
                    item
                );
            }
        }           
    }

我的问题是,当我改成这个时:

    public static async Task openXMLs(string xml)
    {
        XDocument xdoc = XDocument.Load(xml); ;

        if (xdoc != null)
        {
            Task dt1 = Task.Run(() => loadXMLdatatable1(xdoc, xml));
            Task dt2 = Task.Run(() => loadXMLdatatable2(xdoc, xml));

            await Task.WhenAll(dt1, dt2);
        }
    }

我以为我会看到性能提高,但加载时间是一样的。

我这样做是正确的还是无法在任务中运行异步?

【问题讨论】:

  • 我认为您需要附加一个分析器或添加一些其他工具来确定瓶颈在哪里——如果它在内存中查询XDocument,我会感到惊讶。顺便说一句,我注意到XDocument.Load 不能 返回null
  • 将逻辑放在Tasks中然后让逻辑被锁包围的想法是什么?
  • lock 有效地使整个过程串行运行;这里没有真正的并行处理。第一步是通过定时每种方法来进行一些基本的分析以找到瓶颈(使用StopWatch 进行粗略估计)。从那里,您可以开始提出修改后的策略。
  • @CharlesMager 感谢您提供有关 null 的信息,现在我看了看,不知道为什么要这样做。
  • @PeterBons 数据表不是线程安全的,所以我必须在添加记录时锁定它们。这种方法让我加载数据的速度比不使用任务快 3-4 倍。当我最初分析这个过程时,相当多的时间都花在了 Xdocument.Load 上,所以这样做很有帮助。如果你有更好的方法,我会全力以赴。

标签: c# xml asynchronous


【解决方案1】:

使用数据表总是很尴尬,因为它们不支持现代的异步加载概念。因此,在某个特定的时刻,您只需要切换到不同的 UI,或进行其他潜在的重大更改,例如 virtualized data

您能做的最好的事情就是将尽可能多的工作推到锁外。在您的情况下,您有一个查询,但 LINQ 使用deferred execution,因此除非您在lock 之前具体化您的查询,否则实际查询将在锁内执行。

要具体化,您可以在查询结束时致电ToList

public static async Task loadXMLdatatable1(XDocument xdoc, string xml)
{
  var items = xdoc.Elements()
      .Whatever(Long query here for XML)
      .ToList();

  lock(datatable1)
  {
    foreach(var item in items)
    {
      datatable1.Rows.Add(item);
    }
  }           
}

这样,查询将在不持有锁的情况下执行。

如果这不能提供足够的性能改进,或者如果您的查询已经以具体化结束,那么您只需要使用数据虚拟化(可能需要重写 UI)。

【讨论】:

  • 谢谢,ToList() 确实有很大的不同。我不知道具体化和锁定,非常有帮助。
猜你喜欢
  • 1970-01-01
  • 2018-07-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-30
相关资源
最近更新 更多