异步写入文件,但顺序
Writing to a file asynchronously, but in order
我有一些代码可以将对象中的数据保存到 XML。这将 UI 锁定了几秒钟,所以我做到了,所以它不会。
foreach (Path path in m_canvasCompact.Children)
{
Task.Run(() => WritePathDataToXML(false, path));
}
Private void WritePAthDataToXML(bool is32x32, Path path)
{
//stuff going on...
xmlDoc.Root.Descendants.......Add(iconToAdd);
xmlDoc.Save(..);
}
问题是(正如预期的那样)数据写入 XML 的顺序是随机的,具体取决于任务完成的速度(我假设)
我可能会编写一些代码来查看 XML 并在所有内容完成后重新排列它,但这并不理想。有没有办法在一个单独的线程上执行此操作,但也许一次只能执行一个线程,以便它们以正确的顺序执行和保存。
谢谢。
听起来您想要一个 producer/consumer 队列。您可以使用 BlockingCollection<T>
.
相当轻松地组装它
- 创建阻塞集合
- 启动一个任务,该任务将从集合中读取直到 "finished"(最简单的
GetConsumingEnumerable
),然后写入文件
- 将所有相关项目添加到集合中 - 确保您在 UI 线程中执行 涉及 UI 元素的所有内容。
- 告诉集合它是 "finished" (
CompleteAdding
)
或者,如评论中所建议:
- 在 UI 线程中,创建一个包含 UI 元素所需的所有信息的集合 - 基本上您不想在非 - 中触及 UI 元素UI 线程。
- 启动一个任务将该集合写入磁盘;可选地等待该任务(不会阻止 UI)
这更简单,但这确实意味着在开始编写之前在内存中构建整个集合。使用第一种方法,您可以在编写时添加到集合中——尽管如果构建集合比写入磁盘快得多,您完全有可能最终将整个内容都保存在内存中。如果这不可行,您将需要某种方式从 UI 线程添加 "gently",而不阻塞它。如果 BlockingCollection
有一个 AddAsync
方法就好了,但我看不到。
我们对您使用 Path
元素所做的了解还不够多,无法为此提供示例代码,但希望这足以作为一个起点。
运行 整个循环 Task
:
Task.Run(()=>{
foreach (Path path in m_canvasCompact.Children)
{
WritePathDataToXML(false, path);
}
});
这仍然需要相同的时间,但不应阻塞 UI。
我有一些代码可以将对象中的数据保存到 XML。这将 UI 锁定了几秒钟,所以我做到了,所以它不会。
foreach (Path path in m_canvasCompact.Children)
{
Task.Run(() => WritePathDataToXML(false, path));
}
Private void WritePAthDataToXML(bool is32x32, Path path)
{
//stuff going on...
xmlDoc.Root.Descendants.......Add(iconToAdd);
xmlDoc.Save(..);
}
问题是(正如预期的那样)数据写入 XML 的顺序是随机的,具体取决于任务完成的速度(我假设)
我可能会编写一些代码来查看 XML 并在所有内容完成后重新排列它,但这并不理想。有没有办法在一个单独的线程上执行此操作,但也许一次只能执行一个线程,以便它们以正确的顺序执行和保存。
谢谢。
听起来您想要一个 producer/consumer 队列。您可以使用 BlockingCollection<T>
.
- 创建阻塞集合
- 启动一个任务,该任务将从集合中读取直到 "finished"(最简单的
GetConsumingEnumerable
),然后写入文件 - 将所有相关项目添加到集合中 - 确保您在 UI 线程中执行 涉及 UI 元素的所有内容。
- 告诉集合它是 "finished" (
CompleteAdding
)
或者,如评论中所建议:
- 在 UI 线程中,创建一个包含 UI 元素所需的所有信息的集合 - 基本上您不想在非 - 中触及 UI 元素UI 线程。
- 启动一个任务将该集合写入磁盘;可选地等待该任务(不会阻止 UI)
这更简单,但这确实意味着在开始编写之前在内存中构建整个集合。使用第一种方法,您可以在编写时添加到集合中——尽管如果构建集合比写入磁盘快得多,您完全有可能最终将整个内容都保存在内存中。如果这不可行,您将需要某种方式从 UI 线程添加 "gently",而不阻塞它。如果 BlockingCollection
有一个 AddAsync
方法就好了,但我看不到。
我们对您使用 Path
元素所做的了解还不够多,无法为此提供示例代码,但希望这足以作为一个起点。
运行 整个循环 Task
:
Task.Run(()=>{
foreach (Path path in m_canvasCompact.Children)
{
WritePathDataToXML(false, path);
}
});
这仍然需要相同的时间,但不应阻塞 UI。