使用XDocument.Load进行多线程处理

时间:2015-03-04 12:49:35

标签: xml vb.net multithreading linq-to-xml

我正在尝试让我的代码在一个单独的线程中工作,但却无法使其工作。 我尝试使用代理从互联网上跟踪几个不同的多线程示例,但没有解决我的问题。

我需要通过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 个答案:

答案 0 :(得分:8)

如果您使用的是Visual Studio 2012和4.5或更高版本的框架,则可以访问AsyncAwait个关键字,从而使这类内容变得更加容易。但是,您只能在Await对象上使用Task关键字。由于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

但是,通过在Start对象上调用Task方法,可能会启动一个新线程来完成工作。如果你担心解析XML会花费很长时间,那么这是最好的事情,但是如果你只关心下载时间,那么创建一个单独的线程只是让它坐在那里技术上是低效的从URI下载XML时空闲。所以,虽然它有点复杂,但如果你只关心异步执行的下载,那么在技术上做这样的事情会更有效:

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将在框架的某个未来版本中向LoadAsync类添加XDocument方法,但在此之前,您必须自己制作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