【问题标题】:Multithreading with XDocument.Load使用 XDocument.Load 进行多线程
【发布时间】:2015-03-04 12:49:34
【问题描述】:

我试图让我的代码在单独的线程中工作,但无法使其工作。 我尝试使用委托从互联网上遵循几个不同的多线程示例,但没有解决我的问题。

我需要通过 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>

【问题讨论】:

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


    【解决方案1】:

    如果您使用的是 Visual Studio 2012 和 4.5 或更高版本的框架,则可以访问 AsyncAwait 关键字,这会使此类事情变得更加容易。但是,您只能在 Task 对象上使用 Await 关键字。由于XDocument 遗憾地没有提供返回Task 对象的便捷LoadAsync 方法,因此将其与基于任务的异步模式 (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 会花费很长时间,那么无论如何这是最好的做法,但如果您只关心下载时间,那么启动一个单独的线程只是让它坐在那里在技术上是低效的从 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,然后,一旦我们得到它,只需解析XML 字符串将 XDocument 对象返回到调用线程。

    据推测,微软将在框架的某些未来版本中将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
    

    【讨论】:

      猜你喜欢
      • 2023-03-12
      • 2015-09-26
      • 2016-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多