我正在尝试让我的代码在一个单独的线程中工作,但却无法使其工作。 我尝试使用代理从互联网上跟踪几个不同的多线程示例,但没有解决我的问题。
我需要通过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>
答案 0 :(得分:8)
如果您使用的是Visual Studio 2012和4.5或更高版本的框架,则可以访问Async
和Await
个关键字,从而使这类内容变得更加容易。但是,您只能在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