任务内的异步任务
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重写)。
我正在将数百个 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重写)。