任务内的异步任务

Async tasks inside of task

我正在将数百个 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);
        }
    }

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

我这样做是否正确,或者无法在任务内部 运行 异步?

使用数据表总是很尴尬,因为它们不支持异步加载的现代概念。因此,在某个特定点上,您只需要切换到不同的 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重写)。