异步写入文件,但顺序

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>.

相当轻松地组装它
  1. 创建阻塞集合
  2. 启动一个任务,该任务将从集合中读取直到 "finished"(最简单的 GetConsumingEnumerable),然后写入文件
  3. 将所有相关项目添加到集合中 - 确保您在 UI 线程中执行 涉及 UI 元素的所有内容
  4. 告诉集合它是 "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。