【问题标题】:asynchronous threads and anonymous delegates异步线程和匿名委托
【发布时间】:2010-09-20 11:34:33
【问题描述】:

好的,现在我可以使用 2 种技术来启动我的线程:Dispatcher 和 BackgroundWorker。

调度员:

' I launch the asynchronous process
Dim a As New Action(AddressOf operazioneLunga)
a.BeginInvoke(Nothing, Nothing)

' I update the GUI passing some parameters
Dim a As New Action(Of Integer, String)(AddressOf aggiorna_UI)
Me.Dispatcher.BeginInvoke(DispatcherPriority.Normal, a, 5, "pippo")

后台工作人员:

Private bw As BackgroundWorker = Nothing

Private Sub initial()
  bw = New BackgroundWorker
  AddHandler bw.DoWork, AddressOf longOp
  AddHandler bw.RunWorkerCompleted, AddressOf endBGW
  bw.RunWorkerAsync ()
End Sub

Private Sub longOp(ByVal sender As Object, ByVal e As DoWorkEventArgs)
  Dim l As List(Of miaClasse2) = <Long Operation ...>

  e.Result = l
End Sub

Private Sub endBGW(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
  Dim l As List(Of miaClasse2) = e.Result
  Dim be As BindingExpression = BindingOperations.GetBindingExpression(mioDatagrid, DataGrid.ItemsSourceProperty)
  Dim m As miaClasse1 = DirectCast(be.DataItem, miaClasse1)
  m.GetData (l)
  mioDatagrid.UpdateLayout()
  mioDatagrid.ScrollIntoView (mioDatagrid.Items(0))
  RemoveHandler bw.DoWork, AddressOf massiccia
  RemoveHandler bw.RunWorkerCompleted, AddressOf fineBGW
  bw.Dispose()
End Sub

我不知道什么更好,但我想我会使用 BackgroundWorker,因为我想还有其他关于 Dispatcher 的争论我必须知道而且我觉得不安全。

皮莱吉

我之前的帖子:

大家好!

我的应用程序在 WPF / Vb 框架 3.5 SP1 中。我需要在异步线程上执行一些方法。我是这样认识的:

Private Delegate Sub dMassiccia()
Private Delegate Sub dAggiornaUI()

Private Sub iniziale()
  Dim massicciaTemp As New dMassiccia(AddressOf massiccia)
  massicciaTemp.BeginInvoke(Nothing, Nothing)
End Sub

Private Sub massiccia()
  'long operations...
  Me.Dispatcher.BeginInvoke(DispatcherPriority.Normal, _
    New dAggiornaUI(AddressOf aggiornaUI))
End Sub

Private Sub aggiornaUI()
  'update the UI...
End Sub

但是通过这种方式,我必须为我想在异步线程上启动的每个方法声明一个委托,这非常不舒服。我有很多方法可以通过这种方式启动。我知道有匿名代表,但我不知道在这种情况下如何使用它们。 你能帮助我吗? 皮莱吉

附言。其他信息:此时我不需要查找在异步线程中启动的进程的状态。长操作是对 Web 服务的一些请求,每次可能需要几秒钟。线程的数量没有问题,因为我限制了用户启动新线程的可能性,直到其中一个线程完成。除其他原因外,我需要异步线程,因为我不会阻止应用程序,我想用用户控件替换鼠标光标等。

【问题讨论】:

    标签: wpf vb.net visual-studio-2008 asynchronous anonymous-types


    【解决方案1】:

    您想要做什么,需要您启动所有这些线程?看起来您正在创建辅助线程只是为了能够进行 GUI 更新。

    首先,如果您必须创建 很多 个线程,那么您将面临很快耗尽可用线程的风险。我以为最大值只有 64,但文档说每个进程 250,它也可以通过 GetMaxThreadsSetMaxThreads 设置。无论如何,您需要确定使用 ThreadPool 线程(使用 BeginInvoke/EndInvoke 时使用的线程)是否适合您。

    您的 GUI 更新需要多长时间?他们会在您的应用程序的整个持续时间内运行吗?你可以用普通线程代替吗?如果您只需要定期更新状态信息,请考虑使用BackgroundWorker 进行 GUI 更新。在某些情况下,即使是DispatcherTimer 也可以解决问题。这取决于你想做什么。

    您也没有显示所有代码,但在发布的内容中,EndInvoke 未被调用。如果您这样做并最终引发异常,您将无法捕获它并正确处理错误。

    【讨论】:

    • @Dave:非常感谢您的关注。我已经编辑了我的帖子,添加了您问题的答案。我唯一的问题是我想使用匿名委托来编写更少的代码,但我不知道如何。
    • 那么,我建议您进行搜索。 :) 我不是这方面的专家,无法告诉你应该怎么做。当我使用委托时,我的做法与您相同——创建一个委托并将我想在线程中执行的函数传递给它的构造函数。我看不出有什么问题。唯一让我感到惊讶的是您进行 GUI 更新的方法,这似乎有点奇怪。您应该查看其他人发布的有关此方法的内容。
    • @pileggi 只是因为您启动了一个执行大量操作的线程,然后启动另一个线程来执行 GUI 更新。 GUI 只能从主线程更新,所以看起来您正在使用任何似乎方便访问 Dispatcher 的东西。还有其他方法可以从线程进行 GUI 更新,例如 BackgroundWorker。或者,您可以将结果放入共享内存,并通过读取共享内存定期更新您的 GUI。内存必须由关键部分保护,但您始终可以使用 ReaderWriterLockSlim 以获得更好的性能。
    • @Dave:谢谢。我看到你对线程模型非常有能力。我过去使用 BackgroundWorker,但现在我发现在编写更多代码之前我必须学习一下。我只是问你:当我找到解决方案后,我可以再找你征求你的意见吗?我告诉你这个是因为这个论坛很棒,但是如果你花太多时间在下一篇文章上,很难找到仍然回答的人。
    • @pileggi 当然,只需发布​​此问题的更新。仅仅因为我注意到了一些事情,请不要以为我是有能力的。我总是犯很多错误。我随着时间慢慢进步。 :)