XDocument.Load 的多线程
Multithreading with XDocument.Load
我试图让我的代码在单独的线程中运行,但无法运行。
我尝试使用委托从 Internet 获取几个不同的多线程示例,但没有解决我的问题。
我需要通过 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>
如果您使用的是 Visual Studio 2012 和 4.5 框架或更高版本,您可以使用 Async
和 Await
关键字,这会让事情变得更容易。但是,您只能在 Task
对象上使用 Await
关键字。由于 XDocument
很遗憾没有提供 returns 一个 Task
对象的方便的 LoadAsync
方法,因此很难将其与 基于任务的异步模式一起使用(点击)。最简单的方法是创建一个这样的方法:
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
class 确实提供了我们可以使用的基于任务的 Async
方法这一事实。因此,即使XDocument
没有提供基于任务的Async
方法,我们至少仍然可以使用基于任务的WebClient
方法下载XML,然后,一旦我们得到它,只需在调用线程上用 XDocument
对象解析 XML 字符串。
据推测,微软将在框架的某些未来版本中向 XDocument
class 添加一个 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
我试图让我的代码在单独的线程中运行,但无法运行。 我尝试使用委托从 Internet 获取几个不同的多线程示例,但没有解决我的问题。
我需要通过 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>
如果您使用的是 Visual Studio 2012 和 4.5 框架或更高版本,您可以使用 Async
和 Await
关键字,这会让事情变得更容易。但是,您只能在 Task
对象上使用 Await
关键字。由于 XDocument
很遗憾没有提供 returns 一个 Task
对象的方便的 LoadAsync
方法,因此很难将其与 基于任务的异步模式一起使用(点击)。最简单的方法是创建一个这样的方法:
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
class 确实提供了我们可以使用的基于任务的 Async
方法这一事实。因此,即使XDocument
没有提供基于任务的Async
方法,我们至少仍然可以使用基于任务的WebClient
方法下载XML,然后,一旦我们得到它,只需在调用线程上用 XDocument
对象解析 XML 字符串。
据推测,微软将在框架的某些未来版本中向 XDocument
class 添加一个 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