3

I have created a small C# application that should pull all values from an XML file asynchronously. The problem is.. it's not asynchronous and I can't see where I'm going wrong. When the button is clicked the UI freezes, the application can't be moved etc, showing all the signs of it running synchronously.

Can anyone see why this is happening?

private async void parseAndExportBtn_Click(object sender, EventArgs e)
{
    progressBar1.MarqueeAnimationSpeed = 100;
    parseAndExportBtn.Enabled = false;
    selectDirectoryBtn.Enabled = false;
    status.Text = "Started searching files...";
    await SearchFiles(selectTxcDirectory.SelectedPath);
    status.Text = "Finished searching files";
}

private static async Task SearchFiles(string path)
{
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.Load(path + "/cen_18-2_-1-y11.xml");

    using (XmlReader r = XmlReader.Create(new StringReader(xmlDoc.InnerXml), new XmlReaderSettings() { Async = true }))
    {
        while (await r.ReadAsync())
        {
            switch (r.NodeType)
            {
                case XmlNodeType.Text:
                    Console.WriteLine(await r.GetValueAsync());
                    break;
            }
        }
    }
}
jskidd3
  • 4,609
  • 15
  • 63
  • 127
  • 1
    `SearchFiles` needs to be done inside a `Task`. At the moment it is not asynchronous. – Sam Leach Sep 25 '13 at 12:32
  • May be `xmlDoc.Load` makes app to freeze? How long that happens to freeze? – Sriram Sakthivel Sep 25 '13 at 12:32
  • Yes as @sam pointed `SearchFiles` in a `Task` and continuation with Ui thread will be appropriate – Sriram Sakthivel Sep 25 '13 at 12:34
  • 1
    I see nothing asynchronous here. Using `await` means "block until I get a result". You have `await` littered throughout the code.. hence why its blocking. – Simon Whitehead Sep 25 '13 at 12:35
  • @SimonWhitehead Removing await doesn't fix the problem, it still performs synchronously (and creates a warning). – jskidd3 Sep 25 '13 at 12:40
  • @SimonWhitehead: `await` explicitly means to *not* block. It should pause the method *without* blocking the thread. – Stephen Cleary Sep 25 '13 at 12:50
  • When it is littered throughout an entire call stack would it not block? I am sure I have had this issue in production. – Simon Whitehead Sep 25 '13 at 12:57
  • 2
    @SimonWhitehead: `await` actually *has* to be used "all the way up" the call stack for it to behave appropriately - it sort of "grows" through the codebase. If you have a situation where it's blocking, then you should post a question because it certainly should not be doing that. :) – Stephen Cleary Sep 25 '13 at 13:00

2 Answers2

4

Call SearchFiles(string path) in a Task. As below.

private void parseAndExportBtn_Click(object sender, EventArgs e)
{
    progressBar1.MarqueeAnimationSpeed = 100;
    parseAndExportBtn.Enabled = false;
    selectDirectoryBtn.Enabled = false;
    status.Text = "Started searching files...";

    Task t = Task.Run(() => SearchFiles(selectTxcDirectory.SelectedPath));

    status.Text = "Finished searching files";
}

I suggest you read this article on async and await keywords.

Sam Leach
  • 12,746
  • 9
  • 45
  • 73
  • 2
    -1. It is not necessary to wrap I/O-bound operations in a thread pool task, and you shouldn't use `StartNew` for that anyway (as I [describe on my blog](http://blog.stephencleary.com/2013/08/startnew-is-dangerous.html)). – Stephen Cleary Sep 25 '13 at 12:40
  • 2
    This fixed the problem and made the app run asynchronously. :) – jskidd3 Sep 25 '13 at 12:45
3

I'm guessing that the problem is due to XmlDocument.Load, which loads synchronously.

Try using an XmlReader that is created from an asynchronous file stream.

using (var file = new FileStream(path + "/cen_18-2_-1-y11.xml", FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true))
using (XmlReader r = XmlReader.Create(file, new XmlReaderSettings() { Async = true }))
{
    while (await r.ReadAsync())
    {
        switch (r.NodeType)
        {
            case XmlNodeType.Text:
                Console.WriteLine(await r.GetValueAsync());
                break;
        }
    }
}
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810