异步写入文件,但按顺序

Ral*_*alt 2 c# asynchronous

我有一些代码将数据从对象保存到XML.这使得用户界面锁定了几秒钟,所以我做到了这一点.

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(..);
}
Run Code Online (Sandbox Code Playgroud)

问题是(正如预期的那样)数据写入XML的顺序是随机顺序,具体取决于任务完成的速度(我假设)

我可能会写一些代码看到XML的代码,并在完成所有内容后重新排列它,但这并不理想.无论如何要在一个单独的线程上执行此操作,但可能一次只能执行一次,因此它们会以正确的顺序执行并保存.

谢谢.

Jon*_*eet 6

听起来你想要一个生产者/消费者队列.您可以相当轻松地使用它BlockingCollection<T>.

  1. 创建阻止集合
  2. 启动一个将从集合中读取的任务,直到它"完成"(最简单GetConsumingEnumerable),写入文件
  3. 将所有相关项添加到集合中 - 确保您执行触及UI线程中UI元素的所有操作.
  4. 告诉集合它已经"完成"(CompleteAdding)

或者,正如评论中所建议:

  • 在UI线程中,使用UI元素创建一个包含所需信息的集合 - 基本上您不希望触摸非UI线程中的UI元素.
  • 启动任务以将该集合写入磁盘; 可选等待该任务(不会阻止UI)

这更简单,但它确实意味着在开始编写之前在内存中构建整个集合.使用第一种方法,您可以在编写时添加到集合中 - 尽管完全有可能如果构建集合比写入磁盘要快得多,那么无论如何,最终都会在内存中结束.如果这是不可行的,你需要一些方法从UI线程中"轻轻地"添加,而不会阻止它.如果BlockingCollection有一个AddAsync方法会很好,但我看不到一个.

我们对你正在做的Path元素知之甚少,不能为你提供示例代码,但希望这足以成为一个起点.

  • @zaitsman:那个*是一个FIFO队列 - 但是一个线程安全的队列,允许简单的轮询等. (3认同)