Writing to a file asynchronously, but in order

I've got some code which saves data from an object to XML. This locked the UI for a few seconds so I made it so it wouldn't.

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(..);
}

The problem is (as expected) the order in which the data is written to the XML is in a random order depending upon the speed in which the tasks finish (I assume)

I could probably write some bodged code which looks at the XML and rearranges it once everything has been completed, but that's not ideal. Is there anyway to do this on a separate thread, but perhaps only one at a time, so they get executed and saved in the correct order.

Thanks.

Jon Skeet
people
quotationmark

It sounds like you want a producer/consumer queue. You can rig that up fairly easily using BlockingCollection<T>.

  1. Create the blocking collection
  2. Start a task which will read from the collection until it's "finished" (simplest with GetConsumingEnumerable), writing to the file
  3. Add all the relevant items to the collection - making sure you do everything that touches UI elements within the UI thread.
  4. Tell the collection it's "finished" (CompleteAdding)

Alternatively, as suggested in comments:

  • In the UI thread, create a collection with all the information you need from UI elements - basically you don't want to touch the UI elements within a non-UI thread.
  • Start a task to write that collection to disk; optionally await that task (which won't block the UI)

That's simpler, but it does mean building up the whole collection in memory before you start writing. With the first approach, you can add to the collection as you write - although it's entirely possible that if building the collection is much faster than writing to disk, you'll end up with the whole thing in memory anyway. If this is infeasible, you'll need some way of adding "gently" from the UI thread, without blocking it. It would be nice if BlockingCollection had an AddAsync method, but I can't see one.

We don't know enough about what you're doing with the Path elements to give you sample code for this, but hopefully that's enough of a starting point.

people

See more on this question at Stackoverflow