使用XDocument.Load进行多线程操作

4
我正在尝试将我的代码运行在一个独立的线程上,但一直无法使其正常工作。 我已尝试了几个使用委托的多线程示例,但都没有解决我的问题。
我需要通过URL从XML文件中加载数据,然后在标签中显示一些XML数据。由于加载XML有时需要很长时间,因此我的应用程序在加载过程中会停止响应。我不知道还有什么其他方法可以尝试。
下面是一个能够加载XML但未使用多线程(使UI无响应)的示例:
Dim xmlRoot1 As XElement = XDocument.Load("http://example.com/api/books.xml").Root
Label1.Text = xmlRoot1.<bookstore>.<book>(0).<title>.Value
Label2.Text = xmlRoot1.<bookstore>.<book>(1).<title>.Value
' ...

以下是我正在加载的XML示例:

<xml>
<bookstore>
    <book>
        <title>Everyday Italian</title>
        <author>Giada De Laurentiis</author>
        <year>2005</year>
        <price>30.00</price>
    </book>
    <book>
        <title>Harry Potter</title>
        <author>J K. Rowling</author>
        <year>2005</year>
        <price>29.99</price>
    </book>
    <book>
        <title>XQuery Kick Start</title>
        <author>James McGovern</author>
        <year>2003</year>
        <price>49.99</price>
    </book>
    <book>
        <title>Learning XML</title>
        <author>Erik T. Ray</author>
        <year>2003</year>
        <price>39.95</price>
    </book>
    </bookstore>
</xml>
1个回答

8
如果您正在使用Visual Studio 2012和4.5框架或更高版本,您可以访问AsyncAwait关键字,这使得像这样的事情变得更加容易。然而,您只能在Task对象上使用Await关键字。由于XDocument不幸地没有提供方便的LoadAsync方法来返回Task对象,所以使用它与异步模式的任务(TAP)更加困难。最简单的方法是创建一个像这样的方法:
Public Async Function LoadXDocumentAsync(uri As String) As Task(Of XDocument)
    Dim t As New Task(Of XDocument)(Function() XDocument.Load(uri))
    t.Start()
    Return Await t
End Function

然后你可以像这样调用它:
Dim doc As XDocument = Await LoadXDocumentAsync("http://example.com/api/books.xml")
Label1.Text = doc.Root.<bookstore>.<book>(0).<title>.Value
Label2.Text = doc.Root.<bookstore>.<book>(1).<title>.Value

然而,如果您在Task对象上调用Start方法,它很可能会启动一个新线程来完成工作。如果您担心解析XML需要很长时间,那么这是最好的选择,但如果您只关心下载时间,那么单独启动一个线程并让它闲置等待XML从URI下载下来在技术上是低效的。因此,虽然它有点复杂,但如果您只关心异步执行下载操作,那么像这样做在技术上更加高效:
Public Async Function LoadXDocumentAsync(uri As String) As Task(Of XDocument)
    Dim client As New WebClient()
    Return XDocument.Parse(Await client.DownloadStringTaskAsync(uri))
End Function

您可以像第一个示例一样调用它。第二个示例利用了WebClient类提供的基于任务的Async方法,因此即使XDocument没有提供基于任务的Async方法,我们仍然可以使用基于任务的WebClient方法下载XML,然后,在调用线程上使用XDocument对象解析XML字符串。
据推测,Microsoft将在未来的框架版本中向XDocument类添加LoadAsync方法,但在此之前,您需要像我在上面的示例中所做的那样自己创建Async函数。
如果您无法使用TAP,建议使用BackgroundWorker组件。例如:
Public Class Form1
    Private _doc As XDocument

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        BackgroundWorker1.RunWorkerAsync()
    End Sub

    Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        _doc = XDocument.Load("http://example.com/api/books.xml")
    End Sub

    Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
        Label1.Text = _doc.Root.<bookstore>.<book>(0).<title>.Value
        Label2.Text = _doc.Root.<bookstore>.<book>(1).<title>.Value
    End Sub
End Class

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接